Remove UI dependencies to JCR.
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 22 Jul 2022 08:19:15 +0000 (10:19 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 22 Jul 2022 08:19:15 +0000 (10:19 +0200)
265 files changed:
Makefile
jcr/org.argeo.cms.jcr.ui/.classpath [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/.project [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/META-INF/.gitignore [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/bnd.bnd [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/build.properties [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/icons/loading.gif [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/icons/noPic-goldenRatio-640px.png [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/icons/noPic-square-640px.png [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/CmsUiConstants.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/CmsUiProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/LifeCycleUiProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/AbstractFormPart.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/FormColors.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/FormFonts.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/FormToolkit.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/FormUtil.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/IFormColors.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/IFormPart.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/IManagedForm.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/IPartSelectionListener.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/ManagedForm.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/editor/FormEditor.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/editor/FormPage.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/editor/IFormPage.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/EditableLink.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/EditableMultiStringProperty.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/EditablePropertyDate.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/EditablePropertyString.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormConstants.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormEditorHeader.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormPageViewer.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormStyle.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormUtils.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/MarkupValidatorCopy.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/package-info.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/CmsFsBrowser.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/FileDrop.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/FsContextMenu.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/FsStyles.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/package-info.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/internal/Activator.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/internal/JcrContentProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/internal/JcrFileUploadReceiver.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/internal/SimpleEditableImage.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/DefaultRepositoryRegister.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/FullVersioningTreeContentProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/JcrBrowserUtils.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/JcrDClickListener.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/JcrImages.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/JcrTreeContentProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/NodeContentProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/NodeLabelProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/OsgiRepositoryRegister.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/PropertiesContentProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/PropertyLabelProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/RepositoryRegister.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/VersionLabelProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/MaintainedRepositoryElem.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/RemoteRepositoryElem.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/RepositoriesElem.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/RepositoryElem.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/SingleJcrNodeElem.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/WorkspaceElem.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/package-info.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/package-info.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/package-info.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/CmsLink.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/CmsPane.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/DefaultImageManager.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/MenuLink.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SimpleCmsHeader.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SimpleDynamicPages.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SimpleStaticPage.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SimpleStyle.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/StyleSheetResourceLoader.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SystemNotifications.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/UserMenu.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/UserMenuLink.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/VerticalMenu.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/package-info.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/AbstractPageViewer.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/ItemPart.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/JcrVersionCmsEditable.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/NodePart.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/PropertyPart.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/Section.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/SectionPart.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/package-info.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/EditableImage.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/EditableText.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/Img.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/StyledControl.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/TextStyles.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/package-info.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/AbstractNodeContentProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/AsyncUiEventListener.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/DefaultNodeLabelProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/JcrUiUtils.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/NodeColumnLabelProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/NodeElement.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/NodeElementComparer.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/NodesWrapper.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/QueryTableContentProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/RowColumnLabelProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/SimpleNodeContentProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/VersionColumnLabelProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/VersionHistoryContentProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/WrappedNode.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/JcrColumnDefinition.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/NodeViewerComparator.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/RowViewerComparator.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/SimpleJcrNodeLabelProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/SimpleJcrRowLabelProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/package-info.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/package-info.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/JcrFileProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/JcrItemsComparator.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/NodeViewerComparer.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/SingleSessionFileProvider.java [new file with mode: 0644]
jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/package-info.java [new file with mode: 0644]
jcr/org.argeo.cms.ui/.classpath [deleted file]
jcr/org.argeo.cms.ui/.project [deleted file]
jcr/org.argeo.cms.ui/META-INF/.gitignore [deleted file]
jcr/org.argeo.cms.ui/bnd.bnd [deleted file]
jcr/org.argeo.cms.ui/build.properties [deleted file]
jcr/org.argeo.cms.ui/icons/loading.gif [deleted file]
jcr/org.argeo.cms.ui/icons/noPic-goldenRatio-640px.png [deleted file]
jcr/org.argeo.cms.ui/icons/noPic-square-640px.png [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiConstants.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/LifeCycleUiProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/AbstractFormPart.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/FormColors.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/FormFonts.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/FormToolkit.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/FormUtil.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/IFormColors.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/IFormPart.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/IManagedForm.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/IPartSelectionListener.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/ManagedForm.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/editor/FormEditor.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/editor/FormPage.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/editor/IFormPage.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditableLink.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditableMultiStringProperty.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyDate.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyString.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormConstants.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormEditorHeader.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormPageViewer.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormStyle.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormUtils.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/MarkupValidatorCopy.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/package-info.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/CmsFsBrowser.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FileDrop.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FsContextMenu.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FsStyles.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/package-info.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/Activator.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/JcrContentProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/JcrFileUploadReceiver.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/SimpleEditableImage.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/DefaultRepositoryRegister.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/FullVersioningTreeContentProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/JcrBrowserUtils.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/JcrDClickListener.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/JcrImages.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/JcrTreeContentProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/NodeContentProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/NodeLabelProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/OsgiRepositoryRegister.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/PropertiesContentProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/PropertyLabelProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/RepositoryRegister.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/VersionLabelProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/MaintainedRepositoryElem.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/RemoteRepositoryElem.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/RepositoriesElem.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/RepositoryElem.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/SingleJcrNodeElem.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/WorkspaceElem.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/package-info.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/package-info.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/package-info.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsLink.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsPane.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/DefaultImageManager.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/MenuLink.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleCmsHeader.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleDynamicPages.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleImageManager.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStaticPage.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStyle.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/StyleSheetResourceLoader.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SystemNotifications.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenu.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenuLink.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/VerticalMenu.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/package-info.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/AbstractPageViewer.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/ItemPart.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/JcrVersionCmsEditable.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/NodePart.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/PropertyPart.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/Section.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/SectionPart.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/package-info.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableImage.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableText.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/Img.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/StyledControl.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/TextStyles.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/package-info.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/AbstractNodeContentProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/AsyncUiEventListener.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/DefaultNodeLabelProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/JcrUiUtils.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/NodeColumnLabelProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/NodeElement.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/NodeElementComparer.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/NodesWrapper.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/QueryTableContentProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/RowColumnLabelProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/SimpleNodeContentProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/VersionColumnLabelProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/VersionHistoryContentProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/WrappedNode.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/JcrColumnDefinition.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/NodeViewerComparator.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/RowViewerComparator.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/SimpleJcrNodeLabelProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/SimpleJcrRowLabelProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/package-info.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/package-info.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/JcrFileProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/JcrItemsComparator.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/NodeViewerComparer.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/SingleSessionFileProvider.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/package-info.java [deleted file]
org.argeo.cms.ux/src/org/argeo/cms/ux/AbstractImageManager.java [new file with mode: 0644]
org.argeo.cms.ux/src/org/argeo/cms/ux/CmsUxUtils.java
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/AbstractSwtImageManager.java [new file with mode: 0644]
swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/AcrSwtImageManager.java [new file with mode: 0644]
swt/rap/org.argeo.cms.e4.rap/bnd.bnd
swt/rap/org.argeo.cms.e4.rap/src/org/argeo/cms/e4/rap/CmsLoginLifecycle.java
swt/rap/org.argeo.cms.swt.rap/bnd.bnd
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/AppUi.java [deleted file]
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/Branding.java [deleted file]
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/CmsScriptApp.java [deleted file]
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/CmsScriptRwtApplication.java [deleted file]
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/ScriptAppActivator.java [deleted file]
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/ScriptUi.java [deleted file]
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/cms.js [deleted file]
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/package-info.java [deleted file]
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/AbstractCmsEntryPoint.java [deleted file]
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/CmsWebEntryPoint.java
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/SimpleApp.java [deleted file]
swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/SimpleErgonomics.java [deleted file]

index 5c14dc8b1b20cbfb22b0ef1fb3506350999bb9f8..b04cee3063a22ef02d4bff17b7f9006269d61ae8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -41,7 +41,7 @@ swt/rap/org.argeo.cms.swt.rap \
 swt/rap/org.argeo.cms.swt.rap.cli \
 swt/rap/org.argeo.cms.e4.rap \
 jcr/org.argeo.cms.jcr \
-jcr/org.argeo.cms.ui \
+jcr/org.argeo.cms.jcr.ui \
 
 JAVADOC_BUNDLES =  \
 org.argeo.api.uuid \
diff --git a/jcr/org.argeo.cms.jcr.ui/.classpath b/jcr/org.argeo.cms.jcr.ui/.classpath
new file mode 100644 (file)
index 0000000..81fe078
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/jcr/org.argeo.cms.jcr.ui/.project b/jcr/org.argeo.cms.jcr.ui/.project
new file mode 100644 (file)
index 0000000..645296b
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.cms.jcr.ui</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/jcr/org.argeo.cms.jcr.ui/META-INF/.gitignore b/jcr/org.argeo.cms.jcr.ui/META-INF/.gitignore
new file mode 100644 (file)
index 0000000..4854a41
--- /dev/null
@@ -0,0 +1 @@
+/MANIFEST.MF
diff --git a/jcr/org.argeo.cms.jcr.ui/bnd.bnd b/jcr/org.argeo.cms.jcr.ui/bnd.bnd
new file mode 100644 (file)
index 0000000..c3c609c
--- /dev/null
@@ -0,0 +1,23 @@
+Bundle-Activator: org.argeo.cms.ui.internal.Activator
+Bundle-ActivationPolicy: lazy
+
+Import-Package: org.eclipse.swt,\
+org.eclipse.jface.window,\
+org.eclipse.core.commands,\
+javax.jcr.security,\
+org.eclipse.rap.fileupload;version="[2.1,4)",\
+org.eclipse.rap.rwt;version="[2.1,4)",\
+org.eclipse.rap.rwt.application;version="[2.1,4)",\
+org.eclipse.rap.rwt.client;version="[2.1,4)",\
+org.eclipse.rap.rwt.client.service;version="[2.1,4)",\
+org.eclipse.rap.rwt.service;version="[2.1,4)",\
+org.eclipse.rap.rwt.widgets;version="[2.1,4)",\
+org.osgi.*;version=0.0.0,\
+javax.servlet.*;version="[3,5)",\
+*
+
+## TODO: in order to enable single sourcing, we have introduced dummy RAP packages 
+# in the RCP specific bundle org.argeo.eclipse.ui.rap.
+# this was working with RAP 2.x but since we upgrade Rap to 3.1.x, 
+# there is a version range issue cause org.argeo.eclipse.ui.rap bundle is still in 2.x
+# We enable large RAP version range as a workaround that must be fixed 
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/build.properties b/jcr/org.argeo.cms.jcr.ui/build.properties
new file mode 100644 (file)
index 0000000..c6baffa
--- /dev/null
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               icons/
diff --git a/jcr/org.argeo.cms.jcr.ui/icons/loading.gif b/jcr/org.argeo.cms.jcr.ui/icons/loading.gif
new file mode 100644 (file)
index 0000000..3288d10
Binary files /dev/null and b/jcr/org.argeo.cms.jcr.ui/icons/loading.gif differ
diff --git a/jcr/org.argeo.cms.jcr.ui/icons/noPic-goldenRatio-640px.png b/jcr/org.argeo.cms.jcr.ui/icons/noPic-goldenRatio-640px.png
new file mode 100644 (file)
index 0000000..0396506
Binary files /dev/null and b/jcr/org.argeo.cms.jcr.ui/icons/noPic-goldenRatio-640px.png differ
diff --git a/jcr/org.argeo.cms.jcr.ui/icons/noPic-square-640px.png b/jcr/org.argeo.cms.jcr.ui/icons/noPic-square-640px.png
new file mode 100644 (file)
index 0000000..8e3abb5
Binary files /dev/null and b/jcr/org.argeo.cms.jcr.ui/icons/noPic-square-640px.png differ
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/CmsUiConstants.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/CmsUiConstants.java
new file mode 100644 (file)
index 0000000..fd1dda5
--- /dev/null
@@ -0,0 +1,23 @@
+package org.argeo.cms.ui;
+
+/** Commons constants */
+@Deprecated
+public interface CmsUiConstants {
+       // DATAKEYS
+//     public final static String STYLE = EclipseUiConstants.CSS_CLASS;
+//     public final static String MARKUP = EclipseUiConstants.MARKUP_SUPPORT;
+       @Deprecated
+       /* RWT.CUSTOM_ITEM_HEIGHT */
+       public final static String ITEM_HEIGHT = "org.eclipse.rap.rwt.customItemHeight";
+
+       // EVENT DETAILS
+       @Deprecated
+       /* RWT.HYPERLINK */
+       public final static int HYPERLINK = 1 << 26;
+
+       // STANDARD RESOURCES
+       public final static String LOADING_IMAGE = "icons/loading.gif";
+
+       // MISCEALLENEOUS
+       String DATE_TIME_FORMAT = "dd/MM/yyyy, HH:mm";
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/CmsUiProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/CmsUiProvider.java
new file mode 100644 (file)
index 0000000..5f2377b
--- /dev/null
@@ -0,0 +1,51 @@
+package org.argeo.cms.ui;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.acr.Content;
+import org.argeo.cms.jcr.acr.JcrContent;
+import org.argeo.cms.swt.acr.SwtUiProvider;
+import org.argeo.jcr.JcrException;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** Stateless factory building an SWT user interface given a JCR context. */
+public interface CmsUiProvider extends SwtUiProvider {
+       /**
+        * Initialises a user interface.
+        * 
+        * @param parent  the parent composite
+        * @param context a context node (holding the JCR underlying session), or null
+        */
+       default Control createUi(Composite parent, Node context) throws RepositoryException {
+               // does nothing by default
+               return null;
+       }
+
+       default Control createUiPart(Composite parent, Node context) {
+               try {
+                       return createUi(parent, context);
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot create UI for context " + context, e);
+               }
+       }
+
+       @Override
+       default Control createUiPart(Composite parent, Content context) {
+               if (context == null)
+                       return createUiPart(parent, (Node) null);
+               if (context instanceof JcrContent) {
+                       Node node = ((JcrContent) context).getJcrNode();
+                       return createUiPart(parent, node);
+               } else {
+//                     CmsLog.getLog(CmsUiProvider.class)
+//                                     .warn("In " + getClass() + ", content " + context + " is not compatible with JCR.");
+//                     return createUiPart(parent, (Node) null);
+
+                       throw new IllegalArgumentException(
+                                       "In " + getClass() + ", content " + context + " is not compatible with JCR");
+               }
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/LifeCycleUiProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/LifeCycleUiProvider.java
new file mode 100644 (file)
index 0000000..5d77c15
--- /dev/null
@@ -0,0 +1,11 @@
+package org.argeo.cms.ui;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+/** CmsUiProvider notified of initialisation with a system session. */
+public interface LifeCycleUiProvider extends CmsUiProvider {
+       public void init(Session adminSession) throws RepositoryException;
+
+       public void destroy();
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/AbstractFormPart.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/AbstractFormPart.java
new file mode 100644 (file)
index 0000000..4ce4688
--- /dev/null
@@ -0,0 +1,108 @@
+package org.argeo.cms.ui.eclipse.forms;
+/**
+ * AbstractFormPart implements IFormPart interface and can be used as a
+ * convenient base class for concrete form parts. If a method contains
+ * code that must be called, look for instructions to call 'super'
+ * when overriding.
+ * 
+ * @see org.eclipse.ui.forms.widgets.Section
+ * @since 1.0
+ */
+public abstract class AbstractFormPart implements IFormPart {
+       private IManagedForm managedForm;
+       private boolean dirty = false;
+       private boolean stale = true;
+       /**
+        * @see org.eclipse.ui.forms.IFormPart#initialize(org.eclipse.ui.forms.IManagedForm)
+        */
+       public void initialize(IManagedForm form) {
+               this.managedForm = form;
+       }
+       /**
+        * Returns the form that manages this part.
+        * 
+        * @return the managed form
+        */
+       public IManagedForm getManagedForm() {
+               return managedForm;
+       }
+       /**
+        * Disposes the part. Subclasses should override to release any system
+        * resources.
+        */
+       public void dispose() {
+       }
+       /**
+        * Commits the part. Subclasses should call 'super' when overriding.
+        * 
+        * @param onSave
+        *            <code>true</code> if the request to commit has arrived as a
+        *            result of the 'save' action.
+        */
+       public void commit(boolean onSave) {
+               dirty = false;
+       }
+       /**
+        * Sets the overall form input. Subclases may elect to override the method
+        * and adjust according to the form input.
+        * 
+        * @param input
+        *            the form input object
+        * @return <code>false</code>
+        */
+       public boolean setFormInput(Object input) {
+               return false;
+       }
+       /**
+        * Instructs the part to grab keyboard focus.
+        */
+       public void setFocus() {
+       }
+       /**
+        * Refreshes the section after becoming stale (falling behind data in the
+        * model). Subclasses must call 'super' when overriding this method.
+        */
+       public void refresh() {
+               stale = false;
+               // since we have refreshed, any changes we had in the
+               // part are gone and we are not dirty
+               dirty = false;
+       }
+       /**
+        * Marks the part dirty. Subclasses should call this method as a result of
+        * user interaction with the widgets in the section.
+        */
+       public void markDirty() {
+               dirty = true;
+               managedForm.dirtyStateChanged();
+       }
+       /**
+        * Tests whether the part is dirty i.e. its widgets have state that is
+        * newer than the data in the model.
+        * 
+        * @return <code>true</code> if the part is dirty, <code>false</code>
+        *         otherwise.
+        */
+       public boolean isDirty() {
+               return dirty;
+       }
+       /**
+        * Tests whether the part is stale i.e. its widgets have state that is
+        * older than the data in the model.
+        * 
+        * @return <code>true</code> if the part is stale, <code>false</code>
+        *         otherwise.
+        */
+       public boolean isStale() {
+               return stale;
+       }
+       /**
+        * Marks the part stale. Subclasses should call this method as a result of
+        * model notification that indicates that the content of the section is no
+        * longer in sync with the model.
+        */
+       public void markStale() {
+               stale = true;
+               managedForm.staleStateChanged();
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/FormColors.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/FormColors.java
new file mode 100644 (file)
index 0000000..32b031b
--- /dev/null
@@ -0,0 +1,730 @@
+package org.argeo.cms.ui.eclipse.forms;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+//import org.eclipse.swt.internal.graphics.Graphics;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Manages colors that will be applied to forms and form widgets. The colors are
+ * chosen to make the widgets look correct in the editor area. If a different
+ * set of colors is needed, subclass this class and override 'initialize' and/or
+ * 'initializeColors'.
+ * 
+ * @since 1.0
+ */
+public class FormColors {
+       /**
+        * Key for the form title foreground color.
+        * 
+        * @deprecated use <code>IFormColors.TITLE</code>.
+        */
+       public static final String TITLE = IFormColors.TITLE;
+
+       /**
+        * Key for the tree/table border color.
+        * 
+        * @deprecated use <code>IFormColors.BORDER</code>
+        */
+       public static final String BORDER = IFormColors.BORDER;
+
+       /**
+        * Key for the section separator color.
+        * 
+        * @deprecated use <code>IFormColors.SEPARATOR</code>.
+        */
+       public static final String SEPARATOR = IFormColors.SEPARATOR;
+
+       /**
+        * Key for the section title bar background.
+        * 
+        * @deprecated use <code>IFormColors.TB_BG
+        */
+       public static final String TB_BG = IFormColors.TB_BG;
+
+       /**
+        * Key for the section title bar foreground.
+        * 
+        * @deprecated use <code>IFormColors.TB_FG</code>
+        */
+       public static final String TB_FG = IFormColors.TB_FG;
+
+       /**
+        * Key for the section title bar gradient.
+        * 
+        * @deprecated use <code>IFormColors.TB_GBG</code>
+        */
+       public static final String TB_GBG = IFormColors.TB_GBG;
+
+       /**
+        * Key for the section title bar border.
+        * 
+        * @deprecated use <code>IFormColors.TB_BORDER</code>.
+        */
+       public static final String TB_BORDER = IFormColors.TB_BORDER;
+
+       /**
+        * Key for the section toggle color. Since 3.1, this color is used for all
+        * section styles.
+        * 
+        * @deprecated use <code>IFormColors.TB_TOGGLE</code>.
+        */
+       public static final String TB_TOGGLE = IFormColors.TB_TOGGLE;
+
+       /**
+        * Key for the section toggle hover color.
+        * 
+        * @deprecated use <code>IFormColors.TB_TOGGLE_HOVER</code>.
+        */
+       public static final String TB_TOGGLE_HOVER = IFormColors.TB_TOGGLE_HOVER;
+
+       protected Map colorRegistry = new HashMap(10);
+
+       private LocalResourceManager resources;
+
+       protected Color background;
+
+       protected Color foreground;
+
+       private boolean shared;
+
+       protected Display display;
+
+       protected Color border;
+
+       /**
+        * Creates form colors using the provided display.
+        * 
+        * @param display
+        *            the display to use
+        */
+       public FormColors(Display display) {
+               this.display = display;
+               initialize();
+       }
+
+       /**
+        * Returns the display used to create colors.
+        * 
+        * @return the display
+        */
+       public Display getDisplay() {
+               return display;
+       }
+
+       /**
+        * Initializes the colors. Subclasses can override this method to change the
+        * way colors are created. Alternatively, only the color table can be
+        * modified by overriding <code>initializeColorTable()</code>.
+        * 
+        * @see #initializeColorTable
+        */
+       protected void initialize() {
+               background = display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
+               foreground = display.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
+               initializeColorTable();
+               updateBorderColor();
+       }
+
+       /**
+        * Allocates colors for the following keys: BORDER, SEPARATOR and
+        * TITLE. Subclasses can override to allocate these colors differently.
+        */
+       protected void initializeColorTable() {
+               createTitleColor();
+               createColor(IFormColors.SEPARATOR, getColor(IFormColors.TITLE).getRGB());
+               RGB black = getSystemColor(SWT.COLOR_BLACK);
+               RGB borderRGB = getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT);
+               createColor(IFormColors.BORDER, blend(borderRGB, black, 80));
+       }
+
+       /**
+        * Allocates colors for the section tool bar (all the keys that start with
+        * TB). Since these colors are only needed when TITLE_BAR style is used with
+        * the Section widget, they are not needed all the time and are allocated on
+        * demand. Consequently, this method will do nothing if the colors have been
+        * already initialized. Call this method prior to using colors with the TB
+        * keys to ensure they are available.
+        */
+       public void initializeSectionToolBarColors() {
+               if (colorRegistry.containsKey(IFormColors.TB_BG))
+                       return;
+               createTitleBarGradientColors();
+               createTitleBarOutlineColors();
+               createTwistieColors();
+       }
+
+       /**
+        * Allocates additional colors for the form header, namely background
+        * gradients, bottom separator keylines and DND highlights. Since these
+        * colors are only needed for clients that want to use these particular
+        * style of header rendering, they are not needed all the time and are
+        * allocated on demand. Consequently, this method will do nothing if the
+        * colors have been already initialized. Call this method prior to using
+        * color keys with the H_ prefix to ensure they are available.
+        */
+       protected void initializeFormHeaderColors() {
+               if (colorRegistry.containsKey(IFormColors.H_BOTTOM_KEYLINE2))
+                       return;
+               createFormHeaderColors();
+       }
+
+       /**
+        * Returns the RGB value of the system color represented by the code
+        * argument, as defined in <code>SWT</code> class.
+        * 
+        * @param code
+        *            the system color constant as defined in <code>SWT</code>
+        *            class.
+        * @return the RGB value of the system color
+        */
+       public RGB getSystemColor(int code) {
+               return getDisplay().getSystemColor(code).getRGB();
+       }
+
+       /**
+        * Creates the color for the specified key using the provided RGB object.
+        * The color object will be returned and also put into the registry. When
+        * the class is disposed, the color will be disposed with it.
+        * 
+        * @param key
+        *            the unique color key
+        * @param rgb
+        *            the RGB object
+        * @return the allocated color object
+        */
+       public Color createColor(String key, RGB rgb) {
+               // RAP [rh] changes due to missing Color constructor
+//             Color c = getResourceManager().createColor(rgb);
+//             Color prevC = (Color) colorRegistry.get(key);
+//             if (prevC != null && !prevC.isDisposed())
+//                     getResourceManager().destroyColor(prevC.getRGB());
+//             Color c = Graphics.getColor(rgb);
+               Color c = new Color(display, rgb);
+               colorRegistry.put(key, c);        
+               return c;
+       }
+
+       /**
+        * Creates a color that can be used for areas of the form that is inactive.
+        * These areas can contain images, links, controls and other content but are
+        * considered auxilliary to the main content area.
+        * 
+        * <p>
+        * The color should not be disposed because it is managed by this class.
+        * 
+        * @return the inactive form color
+        */
+       public Color getInactiveBackground() {
+               String key = "__ncbg__"; //$NON-NLS-1$
+               Color color = getColor(key);
+               if (color == null) {
+                       RGB sel = getSystemColor(SWT.COLOR_LIST_SELECTION);
+                       // a blend of 95% white and 5% list selection system color
+                       RGB ncbg = blend(sel, getSystemColor(SWT.COLOR_WHITE), 5);
+                       color = createColor(key, ncbg);
+               }
+               return color;
+       }
+
+       /**
+        * Creates the color for the specified key using the provided RGB values.
+        * The color object will be returned and also put into the registry. If
+        * there is already another color object under the same key in the registry,
+        * the existing object will be disposed. When the class is disposed, the
+        * color will be disposed with it.
+        * 
+        * @param key
+        *            the unique color key
+        * @param r
+        *            red value
+        * @param g
+        *            green value
+        * @param b
+        *            blue value
+        * @return the allocated color object
+        */
+       public Color createColor(String key, int r, int g, int b) {
+               return createColor(key, new RGB(r,g,b));
+       }
+
+       /**
+        * Computes the border color relative to the background. Allocated border
+        * color is designed to work well with white. Otherwise, stanard widget
+        * background color will be used.
+        */
+       protected void updateBorderColor() {
+               if (isWhiteBackground())
+                       border = getColor(IFormColors.BORDER);
+               else {
+                       border = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+                       Color bg = getImpliedBackground();
+                       if (border.getRed() == bg.getRed()
+                                       && border.getGreen() == bg.getGreen()
+                                       && border.getBlue() == bg.getBlue())
+                               border = display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW);
+               }
+       }
+
+       /**
+        * Sets the background color. All the toolkits that use this class will
+        * share the same background.
+        * 
+        * @param bg
+        *            background color
+        */
+       public void setBackground(Color bg) {
+               this.background = bg;
+               updateBorderColor();
+               updateFormHeaderColors();
+       }
+
+       /**
+        * Sets the foreground color. All the toolkits that use this class will
+        * share the same foreground.
+        * 
+        * @param fg
+        *            foreground color
+        */
+       public void setForeground(Color fg) {
+               this.foreground = fg;
+       }
+
+       /**
+        * Returns the current background color.
+        * 
+        * @return the background color
+        */
+       public Color getBackground() {
+               return background;
+       }
+
+       /**
+        * Returns the current foreground color.
+        * 
+        * @return the foreground color
+        */
+       public Color getForeground() {
+               return foreground;
+       }
+
+       /**
+        * Returns the computed border color. Border color depends on the background
+        * and is recomputed whenever the background changes.
+        * 
+        * @return the current border color
+        */
+       public Color getBorderColor() {
+               return border;
+       }
+
+       /**
+        * Tests if the background is white. White background has RGB value
+        * 255,255,255.
+        * 
+        * @return <samp>true</samp> if background is white, <samp>false</samp>
+        *         otherwise.
+        */
+       public boolean isWhiteBackground() {
+               Color bg = getImpliedBackground();
+               return bg.getRed() == 255 && bg.getGreen() == 255
+                               && bg.getBlue() == 255;
+       }
+
+       /**
+        * Returns the color object for the provided key or <samp>null </samp> if
+        * not in the registry.
+        * 
+        * @param key
+        *            the color key
+        * @return color object if found, or <samp>null </samp> if not.
+        */
+       public Color getColor(String key) {
+               if (key.startsWith(IFormColors.TB_PREFIX))
+                       initializeSectionToolBarColors();
+               else if (key.startsWith(IFormColors.H_PREFIX))
+                       initializeFormHeaderColors();
+               return (Color) colorRegistry.get(key);
+       }
+
+       /**
+        * Disposes all the colors in the registry.
+        */
+       public void dispose() {
+               if (resources != null)
+                       resources.dispose();
+               resources = null;
+               colorRegistry = null;
+       }
+
+       /**
+        * Marks the colors shared. This prevents toolkits that share this object
+        * from disposing it.
+        */
+       public void markShared() {
+               this.shared = true;
+       }
+
+       /**
+        * Tests if the colors are shared.
+        * 
+        * @return <code>true</code> if shared, <code>false</code> otherwise.
+        */
+       public boolean isShared() {
+               return shared;
+       }
+
+       /**
+        * Blends c1 and c2 based in the provided ratio.
+        * 
+        * @param c1
+        *            first color
+        * @param c2
+        *            second color
+        * @param ratio
+        *            percentage of the first color in the blend (0-100)
+        * @return the RGB value of the blended color
+        */
+       public static RGB blend(RGB c1, RGB c2, int ratio) {
+               int r = blend(c1.red, c2.red, ratio);
+               int g = blend(c1.green, c2.green, ratio);
+               int b = blend(c1.blue, c2.blue, ratio);
+               return new RGB(r, g, b);
+       }
+
+       /**
+        * Tests the source RGB for range.
+        * 
+        * @param rgb
+        *            the tested RGB
+        * @param from
+        *            range start (excluding the value itself)
+        * @param to
+        *            range end (excluding the value itself)
+        * @return <code>true</code> if at least one of the primary colors in the
+        *         source RGB are within the provided range, <code>false</code>
+        *         otherwise.
+        */
+       public static boolean testAnyPrimaryColor(RGB rgb, int from, int to) {
+               if (testPrimaryColor(rgb.red, from, to))
+                       return true;
+               if (testPrimaryColor(rgb.green, from, to))
+                       return true;
+               if (testPrimaryColor(rgb.blue, from, to))
+                       return true;
+               return false;
+       }
+
+       /**
+        * Tests the source RGB for range.
+        * 
+        * @param rgb
+        *            the tested RGB
+        * @param from
+        *            range start (excluding the value itself)
+        * @param to
+        *            tange end (excluding the value itself)
+        * @return <code>true</code> if at least two of the primary colors in the
+        *         source RGB are within the provided range, <code>false</code>
+        *         otherwise.
+        */
+       public static boolean testTwoPrimaryColors(RGB rgb, int from, int to) {
+               int total = 0;
+               if (testPrimaryColor(rgb.red, from, to))
+                       total++;
+               if (testPrimaryColor(rgb.green, from, to))
+                       total++;
+               if (testPrimaryColor(rgb.blue, from, to))
+                       total++;
+               return total >= 2;
+       }
+
+       /**
+        * Blends two primary color components based on the provided ratio.
+        * 
+        * @param v1
+        *            first component
+        * @param v2
+        *            second component
+        * @param ratio
+        *            percentage of the first component in the blend
+        * @return
+        */
+       private static int blend(int v1, int v2, int ratio) {
+               int b = (ratio * v1 + (100 - ratio) * v2) / 100;
+               return Math.min(255, b);
+       }
+
+       private Color getImpliedBackground() {
+               if (getBackground() != null)
+                       return getBackground();
+               return getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+       }
+
+       private static boolean testPrimaryColor(int value, int from, int to) {
+               return value > from && value < to;
+       }
+
+       private void createTitleColor() {
+               /*
+                * RGB rgb = getSystemColor(SWT.COLOR_LIST_SELECTION); // test too light
+                * if (testTwoPrimaryColors(rgb, 120, 151)) rgb = blend(rgb, BLACK, 80);
+                * else if (testTwoPrimaryColors(rgb, 150, 256)) rgb = blend(rgb, BLACK,
+                * 50); createColor(TITLE, rgb);
+                */
+               RGB bg = getImpliedBackground().getRGB();
+               RGB listSelection = getSystemColor(SWT.COLOR_LIST_SELECTION);
+               RGB listForeground = getSystemColor(SWT.COLOR_LIST_FOREGROUND);
+               RGB rgb = listSelection;
+
+               // Group 1
+               // Rule: If at least 2 of the LIST_SELECTION RGB values are equal to or
+               // between 0 and 120, then use 100% LIST_SELECTION as it is (no
+               // additions)
+               // Examples: XP Default, Win Classic Standard, Win High Con White, Win
+               // Classic Marine
+               if (testTwoPrimaryColors(listSelection, -1, 121))
+                       rgb = listSelection;
+               // Group 2
+               // When LIST_BACKGROUND = white (255, 255, 255) or not black, text
+               // colour = LIST_SELECTION @ 100% Opacity + 50% LIST_FOREGROUND over
+               // LIST_BACKGROUND
+               // Rule: If at least 2 of the LIST_SELECTION RGB values are equal to or
+               // between 121 and 255, then add 50% LIST_FOREGROUND to LIST_SELECTION
+               // foreground colour
+               // Examples: Win Vista, XP Silver, XP Olive , Win Classic Plum, OSX
+               // Aqua, OSX Graphite, Linux GTK
+               else if (testTwoPrimaryColors(listSelection, 120, 256)
+                               || (bg.red == 0 && bg.green == 0 && bg.blue == 0))
+                       rgb = blend(listSelection, listForeground, 50);
+               // Group 3
+               // When LIST_BACKGROUND = black (0, 0, 0), text colour = LIST_SELECTION
+               // @ 100% Opacity + 50% LIST_FOREGROUND over LIST_BACKGROUND
+               // Rule: If LIST_BACKGROUND = 0, 0, 0, then add 50% LIST_FOREGROUND to
+               // LIST_SELECTION foreground colour
+               // Examples: Win High Con Black, Win High Con #1, Win High Con #2
+               // (covered in the second part of the OR clause above)
+               createColor(IFormColors.TITLE, rgb);
+       }
+
+       private void createTwistieColors() {
+               RGB rgb = getColor(IFormColors.TITLE).getRGB();
+               RGB white = getSystemColor(SWT.COLOR_WHITE);
+               createColor(TB_TOGGLE, rgb);
+               rgb = blend(rgb, white, 60);
+               createColor(TB_TOGGLE_HOVER, rgb);
+       }
+
+       private void createTitleBarGradientColors() {
+               RGB tbBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
+               RGB bg = getImpliedBackground().getRGB();
+
+               // Group 1
+               // Rule: If at least 2 of the RGB values are equal to or between 180 and
+               // 255, then apply specified opacity for Group 1
+               // Examples: Vista, XP Silver, Wn High Con #2
+               // Gradient Bottom = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
+               // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+               if (testTwoPrimaryColors(tbBg, 179, 256))
+                       tbBg = blend(tbBg, bg, 30);
+
+               // Group 2
+               // Rule: If at least 2 of the RGB values are equal to or between 121 and
+               // 179, then apply specified opacity for Group 2
+               // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
+               // Gradient Bottom = TITLE_BACKGROUND @ 20% Opacity over LIST_BACKGROUND
+               // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+               else if (testTwoPrimaryColors(tbBg, 120, 180))
+                       tbBg = blend(tbBg, bg, 20);
+
+               // Group 3
+               // Rule: Everything else
+               // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
+               // Aqua, Wn High Con White, Wn High Con #1
+               // Gradient Bottom = TITLE_BACKGROUND @ 10% Opacity over LIST_BACKGROUND
+               // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+               else {
+                       tbBg = blend(tbBg, bg, 10);
+               }
+
+               createColor(IFormColors.TB_BG, tbBg);
+               
+               // for backward compatibility
+               createColor(TB_GBG, tbBg);
+       }
+
+       private void createTitleBarOutlineColors() {
+               // title bar outline - border color
+               RGB tbBorder = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
+               RGB bg = getImpliedBackground().getRGB();
+               // Group 1
+               // Rule: If at least 2 of the RGB values are equal to or between 180 and
+               // 255, then apply specified opacity for Group 1
+               // Examples: Vista, XP Silver, Wn High Con #2
+               // Keyline = TITLE_BACKGROUND @ 70% Opacity over LIST_BACKGROUND
+               if (testTwoPrimaryColors(tbBorder, 179, 256))
+                       tbBorder = blend(tbBorder, bg, 70);
+
+               // Group 2
+               // Rule: If at least 2 of the RGB values are equal to or between 121 and
+               // 179, then apply specified opacity for Group 2
+               // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
+
+               // Keyline = TITLE_BACKGROUND @ 50% Opacity over LIST_BACKGROUND
+               else if (testTwoPrimaryColors(tbBorder, 120, 180))
+                       tbBorder = blend(tbBorder, bg, 50);
+
+               // Group 3
+               // Rule: Everything else
+               // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
+               // Aqua, Wn High Con White, Wn High Con #1
+
+               // Keyline = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
+               else {
+                       tbBorder = blend(tbBorder, bg, 30);
+               }
+               createColor(FormColors.TB_BORDER, tbBorder);
+       }
+
+       private void updateFormHeaderColors() {
+               if (colorRegistry.containsKey(IFormColors.H_GRADIENT_END)) {
+                       disposeIfFound(IFormColors.H_GRADIENT_END);
+                       disposeIfFound(IFormColors.H_GRADIENT_START);
+                       disposeIfFound(IFormColors.H_BOTTOM_KEYLINE1);
+                       disposeIfFound(IFormColors.H_BOTTOM_KEYLINE2);
+                       disposeIfFound(IFormColors.H_HOVER_LIGHT);
+                       disposeIfFound(IFormColors.H_HOVER_FULL);
+                       initializeFormHeaderColors();
+               }
+       }
+
+       private void disposeIfFound(String key) {
+               Color color = getColor(key);
+               if (color != null) {
+                       colorRegistry.remove(key);
+               // RAP [rh] changes due to missing Color#dispose()                      
+//                     color.dispose();
+               }
+       }
+
+       private void createFormHeaderColors() {
+               createFormHeaderGradientColors();
+               createFormHeaderKeylineColors();
+               createFormHeaderDNDColors();
+       }
+
+       private void createFormHeaderGradientColors() {
+               RGB titleBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
+               Color bgColor = getImpliedBackground();
+               RGB bg = bgColor.getRGB();
+               RGB bottom, top;
+               // Group 1
+               // Rule: If at least 2 of the RGB values are equal to or between 180 and
+               // 255, then apply specified opacity for Group 1
+               // Examples: Vista, XP Silver, Wn High Con #2
+               // Gradient Bottom = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
+               // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+               if (testTwoPrimaryColors(titleBg, 179, 256)) {
+                       bottom = blend(titleBg, bg, 30);
+                       top = bg;
+               }
+
+               // Group 2
+               // Rule: If at least 2 of the RGB values are equal to or between 121 and
+               // 179, then apply specified opacity for Group 2
+               // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
+               // Gradient Bottom = TITLE_BACKGROUND @ 20% Opacity over LIST_BACKGROUND
+               // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+               else if (testTwoPrimaryColors(titleBg, 120, 180)) {
+                       bottom = blend(titleBg, bg, 20);
+                       top = bg;
+               }
+
+               // Group 3
+               // Rule: If at least 2 of the RGB values are equal to or between 0 and
+               // 120, then apply specified opacity for Group 3
+               // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
+               // Aqua, Wn High Con White, Wn High Con #1
+               // Gradient Bottom = TITLE_BACKGROUND @ 10% Opacity over LIST_BACKGROUND
+               // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
+               else {
+                       bottom = blend(titleBg, bg, 10);
+                       top = bg;
+               }
+               createColor(IFormColors.H_GRADIENT_END, top);
+               createColor(IFormColors.H_GRADIENT_START, bottom);
+       }
+
+       private void createFormHeaderKeylineColors() {
+               RGB titleBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
+               Color bgColor = getImpliedBackground();
+               RGB bg = bgColor.getRGB();
+               RGB keyline2;
+               // H_BOTTOM_KEYLINE1
+               createColor(IFormColors.H_BOTTOM_KEYLINE1, new RGB(255, 255, 255));
+
+               // H_BOTTOM_KEYLINE2
+               // Group 1
+               // Rule: If at least 2 of the RGB values are equal to or between 180 and
+               // 255, then apply specified opacity for Group 1
+               // Examples: Vista, XP Silver, Wn High Con #2
+               // Keyline = TITLE_BACKGROUND @ 70% Opacity over LIST_BACKGROUND
+               if (testTwoPrimaryColors(titleBg, 179, 256))
+                       keyline2 = blend(titleBg, bg, 70);
+
+               // Group 2
+               // Rule: If at least 2 of the RGB values are equal to or between 121 and
+               // 179, then apply specified opacity for Group 2
+               // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
+               // Keyline = TITLE_BACKGROUND @ 50% Opacity over LIST_BACKGROUND
+               else if (testTwoPrimaryColors(titleBg, 120, 180))
+                       keyline2 = blend(titleBg, bg, 50);
+
+               // Group 3
+               // Rule: If at least 2 of the RGB values are equal to or between 0 and
+               // 120, then apply specified opacity for Group 3
+               // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
+               // Aqua, Wn High Con White, Wn High Con #1
+
+               // Keyline = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
+               else
+                       keyline2 = blend(titleBg, bg, 30);
+               // H_BOTTOM_KEYLINE2
+               createColor(IFormColors.H_BOTTOM_KEYLINE2, keyline2);
+       }
+
+       private void createFormHeaderDNDColors() {
+               RGB titleBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND_GRADIENT);
+               Color bgColor = getImpliedBackground();
+               RGB bg = bgColor.getRGB();
+               RGB light, full;
+               // ALL Themes
+               //
+               // Light Highlight
+               // When *near* the 'hot' area
+               // Rule: If near the title in the 'hot' area, show background highlight
+               // TITLE_BACKGROUND_GRADIENT @ 40%
+               light = blend(titleBg, bg, 40);
+               // Full Highlight
+               // When *on* the title area (regions 1 and 2)
+               // Rule: If near the title in the 'hot' area, show background highlight
+               // TITLE_BACKGROUND_GRADIENT @ 60%
+               full = blend(titleBg, bg, 60);
+               // H_DND_LIGHT
+               // H_DND_FULL
+               createColor(IFormColors.H_HOVER_LIGHT, light);
+               createColor(IFormColors.H_HOVER_FULL, full);
+       }
+       
+       private LocalResourceManager getResourceManager() {
+               if (resources == null)
+                       resources = new LocalResourceManager(JFaceResources.getResources());
+               return resources;
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/FormFonts.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/FormFonts.java
new file mode 100644 (file)
index 0000000..9e931ba
--- /dev/null
@@ -0,0 +1,122 @@
+package org.argeo.cms.ui.eclipse.forms;
+
+import java.util.HashMap;
+
+import org.eclipse.jface.resource.DeviceResourceException;
+import org.eclipse.jface.resource.FontDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+//import org.eclipse.swt.internal.graphics.Graphics;
+import org.eclipse.swt.widgets.Display;
+
+public class FormFonts {
+       private static FormFonts instance;
+
+       public static FormFonts getInstance() {
+               if (instance == null)
+                       instance = new FormFonts();
+               return instance;
+       }
+
+       private LocalResourceManager resources;
+       private HashMap descriptors;
+
+       private FormFonts() {
+       }
+
+       private class BoldFontDescriptor extends FontDescriptor {
+               private FontData[] fFontData;
+
+               BoldFontDescriptor(Font font) {
+                       // RAP [if] Changes due to different way of creating fonts
+                       // fFontData = font.getFontData();
+                       // for (int i = 0; i < fFontData.length; i++) {
+                       // fFontData[i].setStyle(fFontData[i].getStyle() | SWT.BOLD);
+                       // }
+                       FontData fontData = font.getFontData()[0];
+                       // Font boldFont = Graphics.getFont( fontData.getName(),
+                       // fontData.getHeight(),
+                       // fontData.getStyle() | SWT.BOLD );
+                       Font boldFont = new Font(Display.getCurrent(), fontData.getName(), fontData.getHeight(),
+                                       fontData.getStyle() | SWT.BOLD);
+                       fFontData = boldFont.getFontData();
+               }
+
+               public boolean equals(Object obj) {
+                       if (obj instanceof BoldFontDescriptor) {
+                               BoldFontDescriptor desc = (BoldFontDescriptor) obj;
+                               if (desc.fFontData.length != fFontData.length)
+                                       return false;
+                               for (int i = 0; i < fFontData.length; i++)
+                                       if (!fFontData[i].equals(desc.fFontData[i]))
+                                               return false;
+                               return true;
+                       }
+                       return false;
+               }
+
+               public int hashCode() {
+                       int hash = 0;
+                       for (int i = 0; i < fFontData.length; i++)
+                               hash = hash * 7 + fFontData[i].hashCode();
+                       return hash;
+               }
+
+               public Font createFont(Device device) throws DeviceResourceException {
+                       // RAP [if] Changes due to different way of creating fonts
+                       return new Font(device, fFontData[0]);
+                       // return Graphics.getFont( fFontData[ 0 ] );
+               }
+
+               public void destroyFont(Font previouslyCreatedFont) {
+                       // RAP [if] unnecessary
+                       // previouslyCreatedFont.dispose();
+               }
+       }
+
+       public Font getBoldFont(Display display, Font font) {
+               checkHashMaps();
+               BoldFontDescriptor desc = new BoldFontDescriptor(font);
+               Font result = getResourceManager().createFont(desc);
+               descriptors.put(result, desc);
+               return result;
+       }
+
+       public boolean markFinished(Font boldFont) {
+               checkHashMaps();
+               BoldFontDescriptor desc = (BoldFontDescriptor) descriptors.get(boldFont);
+               if (desc != null) {
+                       getResourceManager().destroyFont(desc);
+                       if (getResourceManager().find(desc) == null) {
+                               descriptors.remove(boldFont);
+                               validateHashMaps();
+                       }
+                       return true;
+
+               }
+               // if the image was not found, dispose of it for the caller
+               // RAP [if] unnecessary
+               // boldFont.dispose();
+               return false;
+       }
+
+       private LocalResourceManager getResourceManager() {
+               if (resources == null)
+                       resources = new LocalResourceManager(JFaceResources.getResources());
+               return resources;
+       }
+
+       private void checkHashMaps() {
+               if (descriptors == null)
+                       descriptors = new HashMap();
+       }
+
+       private void validateHashMaps() {
+               if (descriptors.size() == 0)
+                       descriptors = null;
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/FormToolkit.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/FormToolkit.java
new file mode 100644 (file)
index 0000000..9927104
--- /dev/null
@@ -0,0 +1,913 @@
+package org.argeo.cms.ui.eclipse.forms;
+
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+//import org.eclipse.swt.custom.CCombo;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+// RAP [rh] Paint events missing
+//import org.eclipse.swt.events.PaintEvent;
+//import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+//RAP [rh] GC missing
+//import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+//import org.eclipse.swt.graphics.RGB;
+//import org.eclipse.swt.graphics.Rectangle;
+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.Event;
+import org.eclipse.swt.widgets.Label;
+//import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.Widget;
+//import org.eclipse.ui.forms.FormColors;
+//import org.eclipse.ui.forms.HyperlinkGroup;
+//import org.eclipse.ui.forms.IFormColors;
+//import org.eclipse.ui.internal.forms.widgets.FormFonts;
+//import org.eclipse.ui.internal.forms.widgets.FormUtil;
+
+/**
+ * The toolkit is responsible for creating SWT controls adapted to work in
+ * Eclipse forms. In addition to changing their presentation properties (fonts,
+ * colors etc.), various listeners are attached to make them behave correctly in
+ * the form context.
+ * <p>
+ * In addition to being the control factory, the toolkit is also responsible for
+ * painting flat borders for select controls, managing hyperlink groups and
+ * control colors.
+ * <p>
+ * The toolkit creates some of the most common controls used to populate Eclipse
+ * forms. Controls that must be created using their constructors,
+ * <code>adapt()</code> method is available to change its properties in the
+ * same way as with the supported toolkit controls.
+ * <p>
+ * Typically, one toolkit object is created per workbench part (for example, an
+ * editor or a form wizard). The toolkit is disposed when the part is disposed.
+ * To conserve resources, it is possible to create one color object for the
+ * entire plug-in and share it between several toolkits. The plug-in is
+ * responsible for disposing the colors (disposing the toolkit that uses shared
+ * color object will not dispose the colors).
+ * <p>
+ * FormToolkit is normally instantiated, but can also be subclassed if some of
+ * the methods needs to be modified. In those cases, <code>super</code> must
+ * be called to preserve normal behaviour.
+ *
+ * @since 1.0
+ */
+public class FormToolkit {
+       public static final String KEY_DRAW_BORDER = "FormWidgetFactory.drawBorder"; //$NON-NLS-1$
+
+       public static final String TREE_BORDER = "treeBorder"; //$NON-NLS-1$
+
+       public static final String TEXT_BORDER = "textBorder"; //$NON-NLS-1$
+
+       private int borderStyle = SWT.NULL;
+
+       private FormColors colors;
+
+       private int orientation = Window.getDefaultOrientation();
+
+       // private KeyListener deleteListener;
+       // RAP [rh] Paint events missing
+//     private BorderPainter borderPainter;
+
+       private BoldFontHolder boldFontHolder;
+
+//     private HyperlinkGroup hyperlinkGroup;
+       
+       private boolean isDisposed = false;
+
+       /* default */
+       VisibilityHandler visibilityHandler;
+
+       /* default */
+       KeyboardHandler keyboardHandler;
+
+       // RAP [rh] Paint events missing
+//     private class BorderPainter implements PaintListener {
+//             public void paintControl(PaintEvent event) {
+//                     Composite composite = (Composite) event.widget;
+//                     Control[] children = composite.getChildren();
+//                     for (int i = 0; i < children.length; i++) {
+//                             Control c = children[i];
+//                             boolean inactiveBorder = false;
+//                             boolean textBorder = false;
+//                             if (!c.isVisible())
+//                                     continue;
+//                             /*
+//                              * if (c.getEnabled() == false && !(c instanceof CCombo))
+//                              * continue;
+//                              */
+//                             if (c instanceof Hyperlink)
+//                                     continue;
+//                             Object flag = c.getData(KEY_DRAW_BORDER);
+//                             if (flag != null) {
+//                                     if (flag.equals(Boolean.FALSE))
+//                                             continue;
+//                                     if (flag.equals(TREE_BORDER))
+//                                             inactiveBorder = true;
+//                                     else if (flag.equals(TEXT_BORDER))
+//                                             textBorder = true;
+//                             }
+//                             if (getBorderStyle() == SWT.BORDER) {
+//                                     if (!inactiveBorder && !textBorder) {
+//                                             continue;
+//                                     }
+//                                     if (c instanceof Text || c instanceof Table
+//                                                     || c instanceof Tree)
+//                                             continue;
+//                             }
+//                             if (!inactiveBorder
+//                                             && (c instanceof Text || c instanceof CCombo || textBorder)) {
+//                                     Rectangle b = c.getBounds();
+//                                     GC gc = event.gc;
+//                                     gc.setForeground(c.getBackground());
+//                                     gc.drawRectangle(b.x - 1, b.y - 1, b.width + 1,
+//                                                     b.height + 1);
+//                                     // gc.setForeground(getBorderStyle() == SWT.BORDER ? colors
+//                                     // .getBorderColor() : colors.getForeground());
+//                                     gc.setForeground(colors.getBorderColor());
+//                                     if (c instanceof CCombo)
+//                                             gc.drawRectangle(b.x - 1, b.y - 1, b.width + 1,
+//                                                             b.height + 1);
+//                                     else
+//                                             gc.drawRectangle(b.x - 1, b.y - 2, b.width + 1,
+//                                                             b.height + 3);
+//                             } else if (inactiveBorder || c instanceof Table
+//                                             || c instanceof Tree) {
+//                                     Rectangle b = c.getBounds();
+//                                     GC gc = event.gc;
+//                                     gc.setForeground(colors.getBorderColor());
+//                                     gc.drawRectangle(b.x - 1, b.y - 1, b.width + 1,
+//                                                     b.height + 1);
+//                             }
+//                     }
+//             }
+//     }
+
+       private static class VisibilityHandler extends FocusAdapter {
+               public void focusGained(FocusEvent e) {
+                       Widget w = e.widget;
+                       if (w instanceof Control) {
+                               FormUtil.ensureVisible((Control) w);
+                       }
+               }
+       }
+
+       private static class KeyboardHandler extends KeyAdapter {
+               public void keyPressed(KeyEvent e) {
+                       Widget w = e.widget;
+                       if (w instanceof Control) {
+                               if (e.doit)
+                                       FormUtil.processKey(e.keyCode, (Control) w);
+                       }
+               }
+       }
+
+       private class BoldFontHolder {
+               private Font normalFont;
+
+               private Font boldFont;
+
+               public BoldFontHolder() {
+               }
+
+               public Font getBoldFont(Font font) {
+                       createBoldFont(font);
+                       return boldFont;
+               }
+
+               private void createBoldFont(Font font) {
+                       if (normalFont == null || !normalFont.equals(font)) {
+                               normalFont = font;
+                               dispose();
+                       }
+                       if (boldFont == null) {
+                               boldFont = FormFonts.getInstance().getBoldFont(colors.getDisplay(),
+                                               normalFont);
+                       }
+               }
+
+               public void dispose() {
+                       if (boldFont != null) {
+                               FormFonts.getInstance().markFinished(boldFont);
+                               boldFont = null;
+                       }
+               }
+       }
+
+       /**
+        * Creates a toolkit that is self-sufficient (will manage its own colors).
+        * <p>
+        * Clients that call this method must call {@link #dispose()} when they
+        * are finished using the toolkit.
+        *
+        */
+       public FormToolkit(Display display) {
+               this(new FormColors(display));
+       }
+
+       /**
+        * Creates a toolkit that will use the provided (shared) colors. The toolkit
+        * will dispose the colors if and only if they are <b>not</b> marked as
+        * shared via the <code>markShared()</code> method.
+        * <p>
+        * Clients that call this method must call {@link #dispose()} when they
+        * are finished using the toolkit.
+        *
+        * @param colors
+        *            the shared colors
+        */
+       public FormToolkit(FormColors colors) {
+               this.colors = colors;
+               initialize();
+       }
+
+       /**
+        * Creates a button as a part of the form.
+        *
+        * @param parent
+        *            the button parent
+        * @param text
+        *            an optional text for the button (can be <code>null</code>)
+        * @param style
+        *            the button style (for example, <code>SWT.PUSH</code>)
+        * @return the button widget
+        */
+       public Button createButton(Composite parent, String text, int style) {
+               Button button = new Button(parent, style | SWT.FLAT | orientation);
+               if (text != null)
+                       button.setText(text);
+               adapt(button, true, true);
+               return button;
+       }
+
+       /**
+        * Creates the composite as a part of the form.
+        *
+        * @param parent
+        *            the composite parent
+        * @return the composite widget
+        */
+       public Composite createComposite(Composite parent) {
+               return createComposite(parent, SWT.NULL);
+       }
+
+       /**
+        * Creates the composite as part of the form using the provided style.
+        *
+        * @param parent
+        *            the composite parent
+        * @param style
+        *            the composite style
+        * @return the composite widget
+        */
+       public Composite createComposite(Composite parent, int style) {
+//             Composite composite = new LayoutComposite(parent, style | orientation);
+               Composite composite = new Composite(parent, style | orientation);
+               adapt(composite);
+               return composite;
+       }
+
+       /**
+        * Creats the composite that can server as a separator between various parts
+        * of a form. Separator height should be controlled by setting the height
+        * hint on the layout data for the composite.
+        *
+        * @param parent
+        *            the separator parent
+        * @return the separator widget
+        */
+// RAP [rh] createCompositeSeparator: currently no useful implementation possible, delete?
+       public Composite createCompositeSeparator(Composite parent) {
+               final Composite composite = new Composite(parent, orientation);
+// RAP [rh] GC and paint events missing
+//             composite.addListener(SWT.Paint, new Listener() {
+//                     public void handleEvent(Event e) {
+//                             if (composite.isDisposed())
+//                                     return;
+//                             Rectangle bounds = composite.getBounds();
+//                             GC gc = e.gc;
+//                             gc.setForeground(colors.getColor(IFormColors.SEPARATOR));
+//                             if (colors.getBackground() != null)
+//                                     gc.setBackground(colors.getBackground());
+//                             gc.fillGradientRectangle(0, 0, bounds.width, bounds.height,
+//                                             false);
+//                     }
+//             });
+//             if (parent instanceof Section)
+//                     ((Section) parent).setSeparatorControl(composite);
+               return composite;
+       }
+
+       /**
+        * Creates a label as a part of the form.
+        *
+        * @param parent
+        *            the label parent
+        * @param text
+        *            the label text
+        * @return the label widget
+        */
+       public Label createLabel(Composite parent, String text) {
+               return createLabel(parent, text, SWT.NONE);
+       }
+
+       /**
+        * Creates a label as a part of the form.
+        *
+        * @param parent
+        *            the label parent
+        * @param text
+        *            the label text
+        * @param style
+        *            the label style
+        * @return the label widget
+        */
+       public Label createLabel(Composite parent, String text, int style) {
+               Label label = new Label(parent, style | orientation);
+               if (text != null)
+                       label.setText(text);
+               adapt(label, false, false);
+               return label;
+       }
+
+       /**
+        * Creates a hyperlink as a part of the form. The hyperlink will be added to
+        * the hyperlink group that belongs to this toolkit.
+        *
+        * @param parent
+        *            the hyperlink parent
+        * @param text
+        *            the text of the hyperlink
+        * @param style
+        *            the hyperlink style
+        * @return the hyperlink widget
+        */
+//     public Hyperlink createHyperlink(Composite parent, String text, int style) {
+//             Hyperlink hyperlink = new Hyperlink(parent, style | orientation);
+//             if (text != null)
+//                     hyperlink.setText(text);
+//             hyperlink.addFocusListener(visibilityHandler);
+//             hyperlink.addKeyListener(keyboardHandler);
+//             hyperlinkGroup.add(hyperlink);
+//             return hyperlink;
+//     }
+
+       /**
+        * Creates an image hyperlink as a part of the form. The hyperlink will be
+        * added to the hyperlink group that belongs to this toolkit.
+        *
+        * @param parent
+        *            the hyperlink parent
+        * @param style
+        *            the hyperlink style
+        * @return the image hyperlink widget
+        */
+//     public ImageHyperlink createImageHyperlink(Composite parent, int style) {
+//             ImageHyperlink hyperlink = new ImageHyperlink(parent, style
+//                             | orientation);
+//             hyperlink.addFocusListener(visibilityHandler);
+//             hyperlink.addKeyListener(keyboardHandler);
+//             hyperlinkGroup.add(hyperlink);
+//             return hyperlink;
+//     }
+
+       /**
+        * Creates a rich text as a part of the form.
+        *
+        * @param parent
+        *            the rich text parent
+        * @param trackFocus
+        *            if <code>true</code>, the toolkit will monitor focus
+        *            transfers to ensure that the hyperlink in focus is visible in
+        *            the form.
+        * @return the rich text widget
+        * @since 1.2
+        */
+//     public FormText createFormText(Composite parent, boolean trackFocus) {
+//             FormText engine = new FormText(parent, SWT.WRAP | orientation);
+//             engine.marginWidth = 1;
+//             engine.marginHeight = 0;
+//             engine.setHyperlinkSettings(getHyperlinkGroup());
+//             adapt(engine, trackFocus, true);
+//             engine.setMenu(parent.getMenu());
+//             return engine;
+//     }
+
+       /**
+        * Adapts a control to be used in a form that is associated with this
+        * toolkit. This involves adjusting colors and optionally adding handlers to
+        * ensure focus tracking and keyboard management.
+        *
+        * @param control
+        *            a control to adapt
+        * @param trackFocus
+        *            if <code>true</code>, form will be scrolled horizontally
+        *            and/or vertically if needed to ensure that the control is
+        *            visible when it gains focus. Set it to <code>false</code> if
+        *            the control is not capable of gaining focus.
+        * @param trackKeyboard
+        *            if <code>true</code>, the control that is capable of
+        *            gaining focus will be tracked for certain keys that are
+        *            important to the underlying form (for example, PageUp,
+        *            PageDown, ScrollUp, ScrollDown etc.). Set it to
+        *            <code>false</code> if the control is not capable of gaining
+        *            focus or these particular key event are already used by the
+        *            control.
+        */
+       public void adapt(Control control, boolean trackFocus, boolean trackKeyboard) {
+               control.setBackground(colors.getBackground());
+               control.setForeground(colors.getForeground());
+//             if (control instanceof ExpandableComposite) {
+//                     ExpandableComposite ec = (ExpandableComposite) control;
+//                     if (ec.toggle != null) {
+//                             if (trackFocus)
+//                                     ec.toggle.addFocusListener(visibilityHandler);
+//                             if (trackKeyboard)
+//                                     ec.toggle.addKeyListener(keyboardHandler);
+//                     }
+//                     if (ec.textLabel != null) {
+//                             if (trackFocus)
+//                                     ec.textLabel.addFocusListener(visibilityHandler);
+//                             if (trackKeyboard)
+//                                     ec.textLabel.addKeyListener(keyboardHandler);
+//                     }
+//                     return;
+//             }
+               if (trackFocus)
+                       control.addFocusListener(visibilityHandler);
+               if (trackKeyboard)
+                       control.addKeyListener(keyboardHandler);
+       }
+
+       /**
+        * Adapts a composite to be used in a form associated with this toolkit.
+        *
+        * @param composite
+        *            the composite to adapt
+        */
+       public void adapt(Composite composite) {
+               composite.setBackground(colors.getBackground());
+               composite.addMouseListener(new MouseAdapter() {
+                       public void mouseDown(MouseEvent e) {
+                               ((Control) e.widget).setFocus();
+                       }
+               });
+               if (composite.getParent() != null)
+                       composite.setMenu(composite.getParent().getMenu());
+       }
+
+       /**
+        * A helper method that ensures the provided control is visible when
+        * ScrolledComposite is somewhere in the parent chain. If scroll bars are
+        * visible and the control is clipped, the client of the scrolled composite
+        * will be scrolled to reveal the control.
+        *
+        * @param c
+        *            the control to reveal
+        */
+       public static void ensureVisible(Control c) {
+               FormUtil.ensureVisible(c);
+       }
+
+       /**
+        * Creates a section as a part of the form.
+        *
+        * @param parent
+        *            the section parent
+        * @param sectionStyle
+        *            the section style
+        * @return the section widget
+        */
+//     public Section createSection(Composite parent, int sectionStyle) {
+//             Section section = new Section(parent, orientation, sectionStyle);
+//             section.setMenu(parent.getMenu());
+//             adapt(section, true, true);
+//             if (section.toggle != null) {
+//                     section.toggle.setHoverDecorationColor(colors
+//                                     .getColor(IFormColors.TB_TOGGLE_HOVER));
+//                     section.toggle.setDecorationColor(colors
+//                                     .getColor(IFormColors.TB_TOGGLE));
+//             }
+//             section.setFont(boldFontHolder.getBoldFont(parent.getFont()));
+//             if ((sectionStyle & Section.TITLE_BAR) != 0
+//                             || (sectionStyle & Section.SHORT_TITLE_BAR) != 0) {
+//                     colors.initializeSectionToolBarColors();
+//                     section.setTitleBarBackground(colors.getColor(IFormColors.TB_BG));
+//                     section.setTitleBarBorderColor(colors
+//                                     .getColor(IFormColors.TB_BORDER));
+//             }
+//             // call setTitleBarForeground regardless as it also sets the label color
+//             section.setTitleBarForeground(colors
+//                             .getColor(IFormColors.TB_TOGGLE));
+//             return section;
+//     }
+
+       /**
+        * Creates an expandable composite as a part of the form.
+        *
+        * @param parent
+        *            the expandable composite parent
+        * @param expansionStyle
+        *            the expandable composite style
+        * @return the expandable composite widget
+        */
+//     public ExpandableComposite createExpandableComposite(Composite parent,
+//                     int expansionStyle) {
+//             ExpandableComposite ec = new ExpandableComposite(parent, orientation,
+//                             expansionStyle);
+//             ec.setMenu(parent.getMenu());
+//             adapt(ec, true, true);
+//             ec.setFont(boldFontHolder.getBoldFont(ec.getFont()));
+//             return ec;
+//     }
+
+       /**
+        * Creates a separator label as a part of the form.
+        *
+        * @param parent
+        *            the separator parent
+        * @param style
+        *            the separator style
+        * @return the separator label
+        */
+       public Label createSeparator(Composite parent, int style) {
+               Label label = new Label(parent, SWT.SEPARATOR | style | orientation);
+               label.setBackground(colors.getBackground());
+               label.setForeground(colors.getBorderColor());
+               return label;
+       }
+
+       /**
+        * Creates a table as a part of the form.
+        *
+        * @param parent
+        *            the table parent
+        * @param style
+        *            the table style
+        * @return the table widget
+        */
+       public Table createTable(Composite parent, int style) {
+               Table table = new Table(parent, style | borderStyle | orientation);
+               adapt(table, false, false);
+               // hookDeleteListener(table);
+               return table;
+       }
+
+       /**
+        * Creates a text as a part of the form.
+        *
+        * @param parent
+        *            the text parent
+        * @param value
+        *            the text initial value
+        * @return the text widget
+        */
+       public Text createText(Composite parent, String value) {
+               return createText(parent, value, SWT.SINGLE);
+       }
+
+       /**
+        * Creates a text as a part of the form.
+        *
+        * @param parent
+        *            the text parent
+        * @param value
+        *            the text initial value
+        * @param style
+        *            the text style
+        * @return the text widget
+        */
+       public Text createText(Composite parent, String value, int style) {
+               Text text = new Text(parent, borderStyle | style | orientation);
+               if (value != null)
+                       text.setText(value);
+               text.setForeground(colors.getForeground());
+               text.setBackground(colors.getBackground());
+               text.addFocusListener(visibilityHandler);
+               return text;
+       }
+
+       /**
+        * Creates a tree widget as a part of the form.
+        *
+        * @param parent
+        *            the tree parent
+        * @param style
+        *            the tree style
+        * @return the tree widget
+        */
+       public Tree createTree(Composite parent, int style) {
+               Tree tree = new Tree(parent, borderStyle | style | orientation);
+               adapt(tree, false, false);
+               // hookDeleteListener(tree);
+               return tree;
+       }
+
+       /**
+        * Creates a scrolled form widget in the provided parent. If you do not
+        * require scrolling because there is already a scrolled composite up the
+        * parent chain, use 'createForm' instead.
+        *
+        * @param parent
+        *            the scrolled form parent
+        * @return the form that can scroll itself
+        * @see #createForm
+        */
+       public ScrolledComposite createScrolledForm(Composite parent) {
+               ScrolledComposite form = new ScrolledComposite(parent, SWT.V_SCROLL
+                               | SWT.H_SCROLL | orientation);
+               form.setExpandHorizontal(true);
+               form.setExpandVertical(true);
+               form.setBackground(colors.getBackground());
+               form.setForeground(colors.getColor(IFormColors.TITLE));
+               form.setFont(JFaceResources.getHeaderFont());
+               return form;
+       }
+
+       /**
+        * Creates a form widget in the provided parent. Note that this widget does
+        * not scroll its content, so make sure there is a scrolled composite up the
+        * parent chain. If you require scrolling, use 'createScrolledForm' instead.
+        *
+        * @param parent
+        *            the form parent
+        * @return the form that does not scroll
+        * @see #createScrolledForm
+        */
+//     public Form createForm(Composite parent) {
+//             Form formContent = new Form(parent, orientation);
+//             formContent.setBackground(colors.getBackground());
+//             formContent.setForeground(colors.getColor(IFormColors.TITLE));
+//             formContent.setFont(JFaceResources.getHeaderFont());
+//             return formContent;
+//     }
+
+       /**
+        * Takes advantage of the gradients and other capabilities to decorate the
+        * form heading using colors computed based on the current skin and
+        * operating system.
+        *
+        * @param form
+        *            the form to decorate
+        */
+
+//     public void decorateFormHeading(Form form) {
+//             Color top = colors.getColor(IFormColors.H_GRADIENT_END);
+//             Color bot = colors.getColor(IFormColors.H_GRADIENT_START);
+//             form.setTextBackground(new Color[] { top, bot }, new int[] { 100 },
+//                             true);
+//             form.setHeadColor(IFormColors.H_BOTTOM_KEYLINE1, colors
+//                             .getColor(IFormColors.H_BOTTOM_KEYLINE1));
+//             form.setHeadColor(IFormColors.H_BOTTOM_KEYLINE2, colors
+//                             .getColor(IFormColors.H_BOTTOM_KEYLINE2));
+//             form.setHeadColor(IFormColors.H_HOVER_LIGHT, colors
+//                             .getColor(IFormColors.H_HOVER_LIGHT));
+//             form.setHeadColor(IFormColors.H_HOVER_FULL, colors
+//                             .getColor(IFormColors.H_HOVER_FULL));
+//             form.setHeadColor(IFormColors.TB_TOGGLE, colors
+//                             .getColor(IFormColors.TB_TOGGLE));
+//             form.setHeadColor(IFormColors.TB_TOGGLE_HOVER, colors
+//                             .getColor(IFormColors.TB_TOGGLE_HOVER));
+//             form.setSeparatorVisible(true);
+//     }
+
+       /**
+        * Creates a scrolled page book widget as a part of the form.
+        *
+        * @param parent
+        *            the page book parent
+        * @param style
+        *            the text style
+        * @return the scrolled page book widget
+        */
+//     public ScrolledPageBook createPageBook(Composite parent, int style) {
+//             ScrolledPageBook book = new ScrolledPageBook(parent, style
+//                             | orientation);
+//             adapt(book, true, true);
+//             book.setMenu(parent.getMenu());
+//             return book;
+//     }
+
+       /**
+        * Disposes the toolkit.
+        */
+       public void dispose() {
+               if (isDisposed) {
+                       return;
+               }
+               isDisposed = true;
+               if (colors.isShared() == false) {
+                       colors.dispose();
+                       colors = null;
+               }
+               boldFontHolder.dispose();
+       }
+
+       /**
+        * Returns the hyperlink group that manages hyperlinks for this toolkit.
+        *
+        * @return the hyperlink group
+        */
+//     public HyperlinkGroup getHyperlinkGroup() {
+//             return hyperlinkGroup;
+//     }
+
+       /**
+        * Sets the background color for the entire toolkit. The method delegates
+        * the call to the FormColors object and also updates the hyperlink group so
+        * that hyperlinks and other objects are in sync.
+        *
+        * @param bg
+        *            the new background color
+        */
+       public void setBackground(Color bg) {
+//             hyperlinkGroup.setBackground(bg);
+               colors.setBackground(bg);
+       }
+
+       /**
+        * Refreshes the hyperlink colors by loading from JFace settings.
+        */
+//     public void refreshHyperlinkColors() {
+//             hyperlinkGroup.initializeDefaultForegrounds(colors.getDisplay());
+//     }
+
+// RAP [rh] paintBordersFor not useful as no GC to actually paint borders
+//     /**
+//      * Paints flat borders for widgets created by this toolkit within the
+//      * provided parent. Borders will not be painted if the global border style
+//      * is SWT.BORDER (i.e. if native borders are used). Call this method during
+//      * creation of a form composite to get the borders of its children painted.
+//      * Care should be taken when selection layout margins. At least one pixel
+//      * pargin width and height must be chosen to allow the toolkit to paint the
+//      * border on the parent around the widgets.
+//      * <p>
+//      * Borders are painted for some controls that are selected by the toolkit by
+//      * default. If a control needs a border but is not on its list, it is
+//      * possible to force border in the following way:
+//      *
+//      * <pre>
+//      *
+//      *
+//      *
+//      *             widget.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER);
+//      *
+//      *             or
+//      *
+//      *             widget.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
+//      *
+//      *
+//      *
+//      * </pre>
+//      *
+//      * @param parent
+//      *            the parent that owns the children for which the border needs
+//      *            to be painted.
+//      */
+//     public void paintBordersFor(Composite parent) {
+//             // if (borderStyle == SWT.BORDER)
+//             // return;
+//             if (borderPainter == null)
+//                     borderPainter = new BorderPainter();
+//             parent.addPaintListener(borderPainter);
+//     }
+
+       /**
+        * Returns the colors used by this toolkit.
+        *
+        * @return the color object
+        */
+       public FormColors getColors() {
+               return colors;
+       }
+
+       /**
+        * Returns the border style used for various widgets created by this
+        * toolkit. The intent of the toolkit is to create controls with styles that
+        * yield a 'flat' appearance. On systems where the native borders are
+        * already flat, we set the style to SWT.BORDER and don't paint the borders
+        * ourselves. Otherwise, the style is set to SWT.NULL, and borders are
+        * painted by the toolkit.
+        *
+        * @return the global border style
+        */
+       public int getBorderStyle() {
+               return borderStyle;
+       }
+
+       /**
+        * Returns the margin required around the children whose border is being
+        * painted by the toolkit using {@link #paintBordersFor(Composite)}. Since
+        * the border is painted around the controls on the parent, a number of
+        * pixels needs to be reserved for this border. For windowing systems where
+        * the native border is used, this margin is 0.
+        *
+        * @return the margin in the parent when children have their border painted
+        */
+       public int getBorderMargin() {
+               return getBorderStyle() == SWT.BORDER ? 0 : 2;
+       }
+
+       /**
+        * Sets the border style to be used when creating widgets. The toolkit
+        * chooses the correct style based on the platform but this value can be
+        * changed using this method.
+        *
+        * @param style
+        *            <code>SWT.BORDER</code> or <code>SWT.NULL</code>
+        * @see #getBorderStyle
+        */
+       public void setBorderStyle(int style) {
+               this.borderStyle = style;
+       }
+
+       /**
+        * A utility method that ensures that the control is visible in the scrolled
+        * composite. The prerequisite for this method is that the control has a
+        * class that extends ScrolledComposite somewhere in the parent chain. If
+        * the control is partially or fully clipped, the composite is scrolled to
+        * set by setting the origin to the control origin.
+        *
+        * @param c
+        *            the control to make visible
+        * @param verticalOnly
+        *            if <code>true</code>, the scrolled composite will be
+        *            scrolled only vertically if needed. Otherwise, the scrolled
+        *            composite origin will be set to the control origin.
+        */
+       public static void setControlVisible(Control c, boolean verticalOnly) {
+               ScrolledComposite scomp = FormUtil.getScrolledComposite(c);
+               if (scomp == null)
+                       return;
+               Point location = FormUtil.getControlLocation(scomp, c);
+               scomp.setOrigin(location);
+       }
+
+       private void initialize() {
+               initializeBorderStyle();
+//             hyperlinkGroup = new HyperlinkGroup(colors.getDisplay());
+//             hyperlinkGroup.setBackground(colors.getBackground());
+               visibilityHandler = new VisibilityHandler();
+               keyboardHandler = new KeyboardHandler();
+               boldFontHolder = new BoldFontHolder();
+       }
+
+// RAP [rh] revise detection of border style: can't ask OS here
+       private void initializeBorderStyle() {
+//             String osname = System.getProperty("os.name"); //$NON-NLS-1$
+//             String osversion = System.getProperty("os.version"); //$NON-NLS-1$
+//             if (osname.startsWith("Windows") && "5.1".compareTo(osversion) <= 0) { //$NON-NLS-1$ //$NON-NLS-2$
+//                     // Skinned widgets used on newer Windows (e.g. XP (5.1), Vista
+//                     // (6.0))
+//                     // Check for Windows Classic. If not used, set the style to BORDER
+//                     RGB rgb = colors.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+//                     if (rgb.red != 212 || rgb.green != 208 || rgb.blue != 200)
+//                             borderStyle = SWT.BORDER;
+//             } else if (osname.startsWith("Mac")) //$NON-NLS-1$
+//                     borderStyle = SWT.BORDER;
+
+               borderStyle = SWT.BORDER;
+       }
+
+       /**
+        * Returns the orientation that all the widgets created by this toolkit will
+        * inherit, if set. Can be <code>SWT.NULL</code>,
+        * <code>SWT.LEFT_TO_RIGHT</code> and <code>SWT.RIGHT_TO_LEFT</code>.
+        *
+        * @return orientation style for this toolkit, or <code>SWT.NULL</code> if
+        *         not set. The default orientation is inherited from the Window
+        *         default orientation.
+        * @see org.eclipse.jface.window.Window#getDefaultOrientation()
+        */
+
+       public int getOrientation() {
+               return orientation;
+       }
+
+       /**
+        * Sets the orientation that all the widgets created by this toolkit will
+        * inherit. Can be <code>SWT.NULL</code>, <code>SWT.LEFT_TO_RIGHT</code>
+        * and <code>SWT.RIGHT_TO_LEFT</code>.
+        *
+        * @param orientation
+        *            style for this toolkit.
+        */
+
+       public void setOrientation(int orientation) {
+               this.orientation = orientation;
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/FormUtil.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/FormUtil.java
new file mode 100644 (file)
index 0000000..76e3f11
--- /dev/null
@@ -0,0 +1,522 @@
+package org.argeo.cms.ui.eclipse.forms;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.MouseEvent;
+//import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+//import org.eclipse.swt.graphics.Image;
+//import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Layout;
+//import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Text;
+//import org.eclipse.ui.forms.widgets.ColumnLayout;
+//import org.eclipse.ui.forms.widgets.Form;
+//import org.eclipse.ui.forms.widgets.FormText;
+//import org.eclipse.ui.forms.widgets.FormToolkit;
+//import org.eclipse.ui.forms.widgets.ILayoutExtension;
+//
+//import com.ibm.icu.text.BreakIterator;
+
+public class FormUtil {
+       public static final String PLUGIN_ID = "org.eclipse.ui.forms"; //$NON-NLS-1$
+
+       static final int H_SCROLL_INCREMENT = 5;
+
+       static final int V_SCROLL_INCREMENT = 64;
+
+       public static final String DEBUG = PLUGIN_ID + "/debug"; //$NON-NLS-1$
+
+       public static final String DEBUG_TEXT = DEBUG + "/text"; //$NON-NLS-1$
+       public static final String DEBUG_TEXTSIZE = DEBUG + "/textsize"; //$NON-NLS-1$
+
+       public static final String DEBUG_FOCUS = DEBUG + "/focus"; //$NON-NLS-1$
+
+       public static final String FOCUS_SCROLLING = "focusScrolling"; //$NON-NLS-1$
+       
+       public static final String IGNORE_BODY = "__ignore_body__"; //$NON-NLS-1$
+
+       public static Text createText(Composite parent, String label,
+                       FormToolkit factory) {
+               return createText(parent, label, factory, 1);
+       }
+
+       public static Text createText(Composite parent, String label,
+                       FormToolkit factory, int span) {
+               factory.createLabel(parent, label);
+               Text text = factory.createText(parent, ""); //$NON-NLS-1$
+               int hfill = span == 1 ? GridData.FILL_HORIZONTAL
+                               : GridData.HORIZONTAL_ALIGN_FILL;
+               GridData gd = new GridData(hfill | GridData.VERTICAL_ALIGN_CENTER);
+               gd.horizontalSpan = span;
+               text.setLayoutData(gd);
+               return text;
+       }
+
+       public static Text createText(Composite parent, String label,
+                       FormToolkit factory, int span, int style) {
+               Label l = factory.createLabel(parent, label);
+               if ((style & SWT.MULTI) != 0) {
+                       GridData gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
+                       l.setLayoutData(gd);
+               }
+               Text text = factory.createText(parent, "", style); //$NON-NLS-1$
+               int hfill = span == 1 ? GridData.FILL_HORIZONTAL
+                               : GridData.HORIZONTAL_ALIGN_FILL;
+               GridData gd = new GridData(hfill | GridData.VERTICAL_ALIGN_CENTER);
+               gd.horizontalSpan = span;
+               text.setLayoutData(gd);
+               return text;
+       }
+
+       public static Text createText(Composite parent, FormToolkit factory,
+                       int span) {
+               Text text = factory.createText(parent, ""); //$NON-NLS-1$
+               int hfill = span == 1 ? GridData.FILL_HORIZONTAL
+                               : GridData.HORIZONTAL_ALIGN_FILL;
+               GridData gd = new GridData(hfill | GridData.VERTICAL_ALIGN_CENTER);
+               gd.horizontalSpan = span;
+               text.setLayoutData(gd);
+               return text;
+       }
+
+       public static int computeMinimumWidth(GC gc, String text) {
+//             BreakIterator wb = BreakIterator.getWordInstance();
+//             wb.setText(text);
+//             int last = 0;
+//
+//             int width = 0;
+//
+//             for (int loc = wb.first(); loc != BreakIterator.DONE; loc = wb.next()) {
+//                     String word = text.substring(last, loc);
+//                     Point extent = gc.textExtent(word);
+//                     width = Math.max(width, extent.x);
+//                     last = loc;
+//             }
+//             String lastWord = text.substring(last);
+//             Point extent = gc.textExtent(lastWord);
+//             width = Math.max(width, extent.x);
+//             return width;
+               return 0;
+       }
+       
+       public static Point computeWrapSize(GC gc, String text, int wHint) {    
+//             BreakIterator wb = BreakIterator.getWordInstance();
+//             wb.setText(text);
+               FontMetrics fm = gc.getFontMetrics();
+               int lineHeight = fm.getHeight();
+               
+               int saved = 0;
+               int last = 0;
+               int height = lineHeight;
+               int maxWidth = 0;
+//             for (int loc = wb.first(); loc != BreakIterator.DONE; loc = wb.next()) {
+//                     String word = text.substring(saved, loc);
+//                     Point extent = gc.textExtent(word);
+//                     if (extent.x > wHint) {
+//                             // overflow
+//                             saved = last;
+//                             height += extent.y;
+//                             // switch to current word so maxWidth will accommodate very long single words
+//                             word = text.substring(last, loc);
+//                             extent = gc.textExtent(word);
+//                     }
+//                     maxWidth = Math.max(maxWidth, extent.x);
+//                     last = loc;
+//             }
+               /*
+                * Correct the height attribute in case it was calculated wrong due to wHint being less than maxWidth.
+                * The recursive call proved to be the only thing that worked in all cases. Some attempts can be made
+                * to estimate the height, but the algorithm needs to be run again to be sure.
+                */
+               if (maxWidth > wHint)
+                       return computeWrapSize(gc, text, maxWidth);               
+               return new Point(maxWidth, height);
+       }
+
+// RAP [rh] paintWrapText unnecessary
+//     public static void paintWrapText(GC gc, String text, Rectangle bounds) {
+//             paintWrapText(gc, text, bounds, false);
+//     }
+       
+// RAP [rh] paintWrapText unnecessary
+//     public static void paintWrapText(GC gc, String text, Rectangle bounds,
+//                     boolean underline) {
+//             BreakIterator wb = BreakIterator.getWordInstance();
+//             wb.setText(text);
+//             FontMetrics fm = gc.getFontMetrics();
+//             int lineHeight = fm.getHeight();
+//             int descent = fm.getDescent();
+//
+//             int saved = 0;
+//             int last = 0;
+//             int y = bounds.y;
+//             int width = bounds.width;
+//
+//             for (int loc = wb.first(); loc != BreakIterator.DONE; loc = wb.next()) {
+//                     String line = text.substring(saved, loc);
+//                     Point extent = gc.textExtent(line);
+//
+//                     if (extent.x > width) {
+//                             // overflow
+//                             String prevLine = text.substring(saved, last);
+//                             gc.drawText(prevLine, bounds.x, y, true);
+//                             if (underline) {
+//                                     Point prevExtent = gc.textExtent(prevLine);
+//                                     int lineY = y + lineHeight - descent + 1;
+//                                     gc
+//                                                     .drawLine(bounds.x, lineY, bounds.x + prevExtent.x,
+//                                                                     lineY);
+//                             }
+//
+//                             saved = last;
+//                             y += lineHeight;
+//                     }
+//                     last = loc;
+//             }
+//             // paint the last line
+//             String lastLine = text.substring(saved, last);
+//             gc.drawText(lastLine, bounds.x, y, true);
+//             if (underline) {
+//                     int lineY = y + lineHeight - descent + 1;
+//                     Point lastExtent = gc.textExtent(lastLine);
+//                     gc.drawLine(bounds.x, lineY, bounds.x + lastExtent.x, lineY);
+//             }
+//     }
+
+       public static ScrolledComposite getScrolledComposite(Control c) {
+               Composite parent = c.getParent();
+
+               while (parent != null) {
+                       if (parent instanceof ScrolledComposite) {
+                               return (ScrolledComposite) parent;
+                       }
+                       parent = parent.getParent();
+               }
+               return null;
+       }
+
+       public static void ensureVisible(Control c) {
+               ScrolledComposite scomp = getScrolledComposite(c);
+               if (scomp != null) {
+                       Object data = scomp.getData(FOCUS_SCROLLING);
+                       if (data == null || !data.equals(Boolean.FALSE))
+                               FormUtil.ensureVisible(scomp, c);
+               }
+       }
+
+       public static void ensureVisible(ScrolledComposite scomp, Control control) {
+               // if the control is a FormText we do not need to scroll since it will
+               // ensure visibility of its segments as necessary
+//             if (control instanceof FormText)
+//                     return;
+               Point controlSize = control.getSize();
+               Point controlOrigin = getControlLocation(scomp, control);
+               ensureVisible(scomp, controlOrigin, controlSize);
+       }
+
+       public static void ensureVisible(ScrolledComposite scomp,
+                       Point controlOrigin, Point controlSize) {
+               Rectangle area = scomp.getClientArea();
+               Point scompOrigin = scomp.getOrigin();
+
+               int x = scompOrigin.x;
+               int y = scompOrigin.y;
+
+               // horizontal right, but only if the control is smaller
+               // than the client area
+               if (controlSize.x < area.width
+                               && (controlOrigin.x + controlSize.x > scompOrigin.x
+                                               + area.width)) {
+                       x = controlOrigin.x + controlSize.x - area.width;
+               }
+               // horizontal left - make sure the left edge of
+               // the control is showing
+               if (controlOrigin.x < x) {
+                       if (controlSize.x < area.width)
+                               x = controlOrigin.x + controlSize.x - area.width;
+                       else
+                               x = controlOrigin.x;
+               }
+               // vertical bottom
+               if (controlSize.y < area.height
+                               && (controlOrigin.y + controlSize.y > scompOrigin.y
+                                               + area.height)) {
+                       y = controlOrigin.y + controlSize.y - area.height;
+               }
+               // vertical top - make sure the top of
+               // the control is showing
+               if (controlOrigin.y < y) {
+                       if (controlSize.y < area.height)
+                               y = controlOrigin.y + controlSize.y - area.height;
+                       else
+                               y = controlOrigin.y;
+               }
+
+               if (scompOrigin.x != x || scompOrigin.y != y) {
+                       // scroll to reveal
+                       scomp.setOrigin(x, y);
+               }
+       }
+
+       public static void ensureVisible(ScrolledComposite scomp, Control control,
+                       MouseEvent e) {
+               Point controlOrigin = getControlLocation(scomp, control);
+               int rX = controlOrigin.x + e.x;
+               int rY = controlOrigin.y + e.y;
+               Rectangle area = scomp.getClientArea();
+               Point scompOrigin = scomp.getOrigin();
+
+               int x = scompOrigin.x;
+               int y = scompOrigin.y;
+               // System.out.println("Ensure: area="+area+", origin="+scompOrigin+",
+               // cloc="+controlOrigin+", csize="+controlSize+", x="+x+", y="+y);
+
+               // horizontal right
+               if (rX > scompOrigin.x + area.width) {
+                       x = rX - area.width;
+               }
+               // horizontal left
+               else if (rX < x) {
+                       x = rX;
+               }
+               // vertical bottom
+               if (rY > scompOrigin.y + area.height) {
+                       y = rY - area.height;
+               }
+               // vertical top
+               else if (rY < y) {
+                       y = rY;
+               }
+
+               if (scompOrigin.x != x || scompOrigin.y != y) {
+                       // scroll to reveal
+                       scomp.setOrigin(x, y);
+               }
+       }
+
+       public static Point getControlLocation(ScrolledComposite scomp,
+                       Control control) {
+               int x = 0;
+               int y = 0;
+               Control content = scomp.getContent();
+               Control currentControl = control;
+               for (;;) {
+                       if (currentControl == content)
+                               break;
+                       Point location = currentControl.getLocation();
+                       // if (location.x > 0)
+                       // x += location.x;
+                       // if (location.y > 0)
+                       // y += location.y;
+                       x += location.x;
+                       y += location.y;
+                       currentControl = currentControl.getParent();
+               }
+               return new Point(x, y);
+       }
+
+       static void scrollVertical(ScrolledComposite scomp, boolean up) {
+               scroll(scomp, 0, up ? -V_SCROLL_INCREMENT : V_SCROLL_INCREMENT);
+       }
+
+       static void scrollHorizontal(ScrolledComposite scomp, boolean left) {
+               scroll(scomp, left ? -H_SCROLL_INCREMENT : H_SCROLL_INCREMENT, 0);
+       }
+
+       static void scrollPage(ScrolledComposite scomp, boolean up) {
+               Rectangle clientArea = scomp.getClientArea();
+               int increment = up ? -clientArea.height : clientArea.height;
+               scroll(scomp, 0, increment);
+       }
+
+       static void scroll(ScrolledComposite scomp, int xoffset, int yoffset) {
+               Point origin = scomp.getOrigin();
+               Point contentSize = scomp.getContent().getSize();
+               int xorigin = origin.x + xoffset;
+               int yorigin = origin.y + yoffset;
+               xorigin = Math.max(xorigin, 0);
+               xorigin = Math.min(xorigin, contentSize.x - 1);
+               yorigin = Math.max(yorigin, 0);
+               yorigin = Math.min(yorigin, contentSize.y - 1);
+               scomp.setOrigin(xorigin, yorigin);
+       }
+
+// RAP [rh] FormUtil#updatePageIncrement: empty implementation
+       public static void updatePageIncrement(ScrolledComposite scomp) {
+//             ScrollBar vbar = scomp.getVerticalBar();
+//             if (vbar != null) {
+//                     Rectangle clientArea = scomp.getClientArea();
+//                     int increment = clientArea.height - 5;
+//                     vbar.setPageIncrement(increment);
+//             }
+//             ScrollBar hbar = scomp.getHorizontalBar();
+//             if (hbar != null) {
+//                     Rectangle clientArea = scomp.getClientArea();
+//                     int increment = clientArea.width - 5;
+//                     hbar.setPageIncrement(increment);
+//             }
+       }
+
+       public static void processKey(int keyCode, Control c) {
+               if (c.isDisposed()) {
+                       return;
+               }
+               ScrolledComposite scomp = FormUtil.getScrolledComposite(c);
+               if (scomp != null) {
+                       if (c instanceof Combo)
+                               return;
+                       switch (keyCode) {
+                       case SWT.ARROW_DOWN:
+                               if (scomp.getData("novarrows") == null) //$NON-NLS-1$
+                                       FormUtil.scrollVertical(scomp, false);
+                               break;
+                       case SWT.ARROW_UP:
+                               if (scomp.getData("novarrows") == null) //$NON-NLS-1$
+                                       FormUtil.scrollVertical(scomp, true);
+                               break;
+                       case SWT.ARROW_LEFT:
+                               FormUtil.scrollHorizontal(scomp, true);
+                               break;
+                       case SWT.ARROW_RIGHT:
+                               FormUtil.scrollHorizontal(scomp, false);
+                               break;
+                       case SWT.PAGE_UP:
+                               FormUtil.scrollPage(scomp, true);
+                               break;
+                       case SWT.PAGE_DOWN:
+                               FormUtil.scrollPage(scomp, false);
+                               break;
+                       }
+               }
+       }
+
+       public static boolean isWrapControl(Control c) {
+               if ((c.getStyle() & SWT.WRAP) != 0)
+                       return true;
+               if (c instanceof Composite) {
+                       return false;
+//                     return ((Composite) c).getLayout() instanceof ILayoutExtension;
+               }
+               return false;
+       }
+
+       public static int getWidthHint(int wHint, Control c) {
+               boolean wrap = isWrapControl(c);
+               return wrap ? wHint : SWT.DEFAULT;
+       }
+
+       public static int getHeightHint(int hHint, Control c) {
+               if (c instanceof Composite) {
+                       Layout layout = ((Composite) c).getLayout();
+//                     if (layout instanceof ColumnLayout)
+//                             return hHint;
+               }
+               return SWT.DEFAULT;
+       }
+
+       public static int computeMinimumWidth(Control c, boolean changed) {
+               if (c instanceof Composite) {
+                       Layout layout = ((Composite) c).getLayout();
+//                     if (layout instanceof ILayoutExtension)
+//                             return ((ILayoutExtension) layout).computeMinimumWidth(
+//                                             (Composite) c, changed);
+               }
+               return c.computeSize(FormUtil.getWidthHint(5, c), SWT.DEFAULT, changed).x;
+       }
+
+       public static int computeMaximumWidth(Control c, boolean changed) {
+               if (c instanceof Composite) {
+                       Layout layout = ((Composite) c).getLayout();
+//                     if (layout instanceof ILayoutExtension)
+//                             return ((ILayoutExtension) layout).computeMaximumWidth(
+//                                             (Composite) c, changed);
+               }
+               return c.computeSize(SWT.DEFAULT, SWT.DEFAULT, changed).x;
+       }
+
+//     public static Form getForm(Control c) {
+//             Composite parent = c.getParent();
+//             while (parent != null) {
+//                     if (parent instanceof Form) {
+//                             return (Form) parent;
+//                     }
+//                     parent = parent.getParent();
+//             }
+//             return null;
+//     }
+
+// RAP [rh] FormUtil#createAlphaMashImage unnecessary  
+//     public static Image createAlphaMashImage(Device device, Image srcImage) {
+//             Rectangle bounds = srcImage.getBounds();
+//             int alpha = 0;
+//             int calpha = 0;
+//             ImageData data = srcImage.getImageData();
+//             // Create a new image with alpha values alternating
+//             // between fully transparent (0) and fully opaque (255).
+//             // This image will show the background through the
+//             // transparent pixels.
+//             for (int i = 0; i < bounds.height; i++) {
+//                     // scan line
+//                     alpha = calpha;
+//                     for (int j = 0; j < bounds.width; j++) {
+//                             // column
+//                             data.setAlpha(j, i, alpha);
+//                             alpha = alpha == 255 ? 0 : 255;
+//                     }
+//                     calpha = calpha == 255 ? 0 : 255;
+//             }
+//             return new Image(device, data);
+//     }
+
+       public static boolean mnemonicMatch(String text, char key) {
+               char mnemonic = findMnemonic(text);
+               if (mnemonic == '\0')
+                       return false;
+               return Character.toUpperCase(key) == Character.toUpperCase(mnemonic);
+       }
+
+       private static char findMnemonic(String string) {
+               int index = 0;
+               int length = string.length();
+               do {
+                       while (index < length && string.charAt(index) != '&')
+                               index++;
+                       if (++index >= length)
+                               return '\0';
+                       if (string.charAt(index) != '&')
+                               return string.charAt(index);
+                       index++;
+               } while (index < length);
+               return '\0';
+       }
+       
+       public static void setFocusScrollingEnabled(Control c, boolean enabled) {
+               ScrolledComposite scomp = null;
+               
+               if (c instanceof ScrolledComposite)
+                       scomp = (ScrolledComposite)c;
+               else
+                       scomp = getScrolledComposite(c);
+               if (scomp!=null)
+                       scomp.setData(FormUtil.FOCUS_SCROLLING, enabled?null:Boolean.FALSE);
+       }
+       
+       // RAP [rh] FormUtil#setAntialias unnecessary
+//     public static void setAntialias(GC gc, int style) {
+//             if (!gc.getAdvanced()) {
+//                     gc.setAdvanced(true);
+//                     if (!gc.getAdvanced())
+//                             return;
+//             }
+//             gc.setAntialias(style);
+//     }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/IFormColors.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/IFormColors.java
new file mode 100644 (file)
index 0000000..cf0e5d3
--- /dev/null
@@ -0,0 +1,102 @@
+package org.argeo.cms.ui.eclipse.forms;
+
+/**
+ * A place to hold all the color constants used in the forms package.
+ * 
+ * @since 1.0
+ */
+
+public interface IFormColors {
+       /**
+        * A prefix for all the keys.
+        */
+       String PREFIX = "org.eclipse.ui.forms."; //$NON-NLS-1$
+       /**
+        * Key for the form title foreground color.
+        */
+       String TITLE = PREFIX + "TITLE"; //$NON-NLS-1$
+
+       /**
+        * A prefix for the header color constants.
+        */
+       String H_PREFIX = PREFIX + "H_"; //$NON-NLS-1$
+       /*
+        * A prefix for the section title bar color constants.
+        */
+       String TB_PREFIX = PREFIX + "TB_"; //$NON-NLS-1$        
+       /**
+        * Key for the form header background gradient ending color.
+        */
+       String H_GRADIENT_END = H_PREFIX + "GRADIENT_END"; //$NON-NLS-1$
+
+       /**
+        * Key for the form header background gradient starting color.
+        * 
+        */
+       String H_GRADIENT_START = H_PREFIX + "GRADIENT_START"; //$NON-NLS-1$
+       /**
+        * Key for the form header bottom keyline 1 color.
+        * 
+        */
+       String H_BOTTOM_KEYLINE1 = H_PREFIX + "BOTTOM_KEYLINE1"; //$NON-NLS-1$
+       /**
+        * Key for the form header bottom keyline 2 color.
+        * 
+        */
+       String H_BOTTOM_KEYLINE2 = H_PREFIX + "BOTTOM_KEYLINE2"; //$NON-NLS-1$
+       /**
+        * Key for the form header light hover color.
+        * 
+        */
+       String H_HOVER_LIGHT = H_PREFIX + "H_HOVER_LIGHT"; //$NON-NLS-1$
+       /**
+        * Key for the form header full hover color.
+        * 
+        */
+       String H_HOVER_FULL = H_PREFIX + "H_HOVER_FULL"; //$NON-NLS-1$
+
+       /**
+        * Key for the tree/table border color.
+        */
+       String BORDER = PREFIX + "BORDER"; //$NON-NLS-1$
+
+       /**
+        * Key for the section separator color.
+        */
+       String SEPARATOR = PREFIX + "SEPARATOR"; //$NON-NLS-1$
+
+       /**
+        * Key for the section title bar background.
+        */
+       String TB_BG = TB_PREFIX + "BG"; //$NON-NLS-1$
+
+       /**
+        * Key for the section title bar foreground.
+        */
+       String TB_FG = TB_PREFIX + "FG"; //$NON-NLS-1$
+
+       /**
+        * Key for the section title bar gradient.
+        * @deprecated Since 3.3, this color is not used any more. The 
+        * tool bar gradient is created starting from {@link #TB_BG} to
+        * the section background color.
+        */
+       String TB_GBG = TB_BG;
+
+       /**
+        * Key for the section title bar border.
+        */
+       String TB_BORDER = TB_PREFIX + "BORDER"; //$NON-NLS-1$
+
+       /**
+        * Key for the section toggle color. Since 3.1, this color is used for all
+        * section styles.
+        */
+       String TB_TOGGLE = TB_PREFIX + "TOGGLE"; //$NON-NLS-1$
+
+       /**
+        * Key for the section toggle hover color.
+        * 
+        */
+       String TB_TOGGLE_HOVER = TB_PREFIX + "TOGGLE_HOVER"; //$NON-NLS-1$              
+}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/IFormPart.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/IFormPart.java
new file mode 100644 (file)
index 0000000..954cc03
--- /dev/null
@@ -0,0 +1,108 @@
+package org.argeo.cms.ui.eclipse.forms;
+
+/**
+ * Classes that implement this interface can be added to the managed form and
+ * take part in the form life cycle. The part is initialized with the form and
+ * will be asked to accept focus. The part can receive form input and can elect
+ * to do something according to it (for example, select an object that matches
+ * the input).
+ * <p>
+ * The form part has two 'out of sync' states in respect to the model(s) that
+ * feed the form: <b>dirty</b> and <b>stale</b>. When a part is dirty, it
+ * means that the user interacted with it and now its widgets contain state that
+ * is newer than the model. In order to sync up with the model, 'commit' needs
+ * to be called. In contrast, the model can change 'under' the form (as a result
+ * of some actions outside the form), resulting in data in the model being
+ * 'newer' than the content presented in the form. A 'stale' form part is
+ * brought in sync with the model by calling 'refresh'. The part is responsible
+ * for notifying the form when one of these states change in the part. The form
+ * reserves the right to handle this notification in the most appropriate way
+ * for the situation (for example, if the form is in a page of the multi-page
+ * editor, it may do nothing for stale parts if the page is currently not
+ * showing).
+ * <p>
+ * When the form is disposed, each registered part is disposed as well. Parts
+ * are responsible for releasing any system resources they created and for
+ * removing themselves as listeners from all event providers.
+ * 
+ * @see IManagedForm
+ * @since 1.0
+ * 
+ */
+public interface IFormPart {
+       /**
+        * Initializes the part.
+        * 
+        * @param form
+        *            the managed form that manages the part
+        */
+       void initialize(IManagedForm form);
+
+       /**
+        * Disposes the part allowing it to release allocated resources.
+        */
+       void dispose();
+
+       /**
+        * Returns true if the part has been modified with respect to the data
+        * loaded from the model.
+        * 
+        * @return true if the part has been modified with respect to the data
+        *         loaded from the model
+        */
+       boolean isDirty();
+
+       /**
+        * If part is displaying information loaded from a model, this method
+        * instructs it to commit the new (modified) data back into the model.
+        * 
+        * @param onSave
+        *            indicates if commit is called during 'save' operation or for
+        *            some other reason (for example, if form is contained in a
+        *            wizard or a multi-page editor and the user is about to leave
+        *            the page).
+        */
+       void commit(boolean onSave);
+
+       /**
+        * Notifies the part that an object has been set as overall form's input.
+        * The part can elect to react by revealing or selecting the object, or do
+        * nothing if not applicable.
+        * 
+        * @return <code>true</code> if the part has selected and revealed the
+        *         input object, <code>false</code> otherwise.
+        */
+       boolean setFormInput(Object input);
+
+       /**
+        * Instructs form part to transfer focus to the widget that should has focus
+        * in that part. The method can do nothing (if it has no widgets capable of
+        * accepting focus).
+        */
+       void setFocus();
+
+       /**
+        * Tests whether the form part is stale and needs refreshing. Parts can
+        * receive notification from models that will make their content stale, but
+        * may need to delay refreshing to improve performance (for example, there
+        * is no need to immediately refresh a part on a form that is current on a
+        * hidden page).
+        * <p>
+        * It is important to differentiate 'stale' and 'dirty' states. Part is
+        * 'dirty' if user interacted with its editable widgets and changed the
+        * values. In contrast, part is 'stale' when the data it presents in the
+        * widgets has been changed in the model without direct user interaction.
+        * 
+        * @return <code>true</code> if the part needs refreshing,
+        *         <code>false</code> otherwise.
+        */
+       boolean isStale();
+
+       /**
+        * Refreshes the part completely from the information freshly obtained from
+        * the model. The method will not be called if the part is not stale.
+        * Otherwise, the part is responsible for clearing the 'stale' flag after
+        * refreshing itself.
+        */
+       void refresh();
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/IManagedForm.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/IManagedForm.java
new file mode 100644 (file)
index 0000000..490d3a3
--- /dev/null
@@ -0,0 +1,175 @@
+package org.argeo.cms.ui.eclipse.forms;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.custom.ScrolledComposite;
+//import org.eclipse.ui.forms.widgets.FormToolkit;
+//import org.eclipse.ui.forms.widgets.ScrolledForm;
+
+/**
+ * Managed form wraps a form widget and adds life cycle methods for form parts.
+ * A form part is a portion of the form that participates in form life cycle
+ * events.
+ * <p>
+ * There is no 1/1 mapping between widgets and form parts. A widget like Section
+ * can be a part by itself, but a number of widgets can gather around one form
+ * part.
+ * <p>
+ * This interface should not be extended or implemented. New form instances
+ * should be created using ManagedForm.
+ * 
+ * @see ManagedForm
+ * @since 1.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface IManagedForm {
+       /**
+        * Initializes the form by looping through the managed parts and
+        * initializing them. Has no effect if already called once.
+        */
+       public void initialize();
+
+       /**
+        * Returns the toolkit used by this form.
+        * 
+        * @return the toolkit
+        */
+       public FormToolkit getToolkit();
+
+       /**
+        * Returns the form widget managed by this form.
+        * 
+        * @return the form widget
+        */
+       public ScrolledComposite getForm();
+
+       /**
+        * Reflows the form as a result of the layout change.
+        * 
+        * @param changed
+        *            if <code>true</code>, discard cached layout information
+        */
+       public void reflow(boolean changed);
+
+       /**
+        * A part can use this method to notify other parts that implement
+        * IPartSelectionListener about selection changes.
+        * 
+        * @param part
+        *            the part that broadcasts the selection
+        * @param selection
+        *            the selection in the part
+        */
+       public void fireSelectionChanged(IFormPart part, ISelection selection);
+
+       /**
+        * Returns all the parts currently managed by this form.
+        * 
+        * @return the managed parts
+        */
+       IFormPart[] getParts();
+
+       /**
+        * Adds the new part to the form.
+        * 
+        * @param part
+        *            the part to add
+        */
+       void addPart(IFormPart part);
+
+       /**
+        * Removes the part from the form.
+        * 
+        * @param part
+        *            the part to remove
+        */
+       void removePart(IFormPart part);
+
+       /**
+        * Sets the input of this page to the provided object.
+        * 
+        * @param input
+        *            the new page input
+        * @return <code>true</code> if the form contains this object,
+        *         <code>false</code> otherwise.
+        */
+       boolean setInput(Object input);
+
+       /**
+        * Returns the current page input.
+        * 
+        * @return page input object or <code>null</code> if not applicable.
+        */
+       Object getInput();
+
+       /**
+        * Tests if form is dirty. A managed form is dirty if at least one managed
+        * part is dirty.
+        * 
+        * @return <code>true</code> if at least one managed part is dirty,
+        *         <code>false</code> otherwise.
+        */
+       boolean isDirty();
+
+       /**
+        * Notifies the form that the dirty state of one of its parts has changed.
+        * The global dirty state of the form can be obtained by calling 'isDirty'.
+        * 
+        * @see #isDirty
+        */
+       void dirtyStateChanged();
+
+       /**
+        * Commits the dirty form. All pending changes in the widgets are flushed
+        * into the model.
+        * 
+        * @param onSave
+        */
+       void commit(boolean onSave);
+
+       /**
+        * Tests if form is stale. A managed form is stale if at least one managed
+        * part is stale. This can happen when the underlying model changes,
+        * resulting in the presentation of the part being out of sync with the
+        * model and needing refreshing.
+        * 
+        * @return <code>true</code> if the form is stale, <code>false</code>
+        *         otherwise.
+        */
+       boolean isStale();
+
+       /**
+        * Notifies the form that the stale state of one of its parts has changed.
+        * The global stale state of the form can be obtained by calling 'isStale'.
+        */
+       void staleStateChanged();
+
+       /**
+        * Refreshes the form by refreshing every part that is stale.
+        */
+       void refresh();
+
+       /**
+        * Sets the container that owns this form. Depending on the context, the
+        * container may be wizard, editor page, editor etc.
+        * 
+        * @param container
+        *            the container of this form
+        */
+       void setContainer(Object container);
+
+       /**
+        * Returns the container of this form.
+        * 
+        * @return the form container
+        */
+       Object getContainer();
+
+       /**
+        * Returns the message manager that will keep track of messages in this
+        * form.
+        * 
+        * @return the message manager instance
+        */
+//     IMessageManager getMessageManager();
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/IPartSelectionListener.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/IPartSelectionListener.java
new file mode 100644 (file)
index 0000000..0f557d4
--- /dev/null
@@ -0,0 +1,23 @@
+package org.argeo.cms.ui.eclipse.forms;
+
+import org.eclipse.jface.viewers.ISelection;
+
+/**
+ * Form parts can implement this interface if they want to be 
+ * notified when another part on the same form changes selection 
+ * state.
+ * 
+ * @see IFormPart
+ * @since 1.0
+ */
+public interface IPartSelectionListener {
+       /**
+        * Called when the provided part has changed selection state.
+        * 
+        * @param part
+        *            the selection source
+        * @param selection
+        *            the new selection
+        */
+       public void selectionChanged(IFormPart part, ISelection selection);
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/ManagedForm.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/ManagedForm.java
new file mode 100644 (file)
index 0000000..4140465
--- /dev/null
@@ -0,0 +1,323 @@
+package org.argeo.cms.ui.eclipse.forms;
+
+import java.util.Vector;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.widgets.Composite;
+//import org.eclipse.ui.forms.widgets.FormToolkit;
+//import org.eclipse.ui.forms.widgets.ScrolledForm;
+
+/**
+ * Managed form wraps a form widget and adds life cycle methods for form parts.
+ * A form part is a portion of the form that participates in form life cycle
+ * events.
+ * <p>
+ * There is requirement for 1/1 mapping between widgets and form parts. A widget
+ * like Section can be a part by itself, but a number of widgets can join around
+ * one form part.
+ * <p>
+ * Note to developers: this class is left public to allow its use beyond the
+ * original intention (inside a multi-page editor's page). You should limit the
+ * use of this class to make new instances inside a form container (wizard page,
+ * dialog etc.). Clients that need access to the class should not do it
+ * directly. Instead, they should do it through IManagedForm interface as much
+ * as possible.
+ * 
+ * @since 1.0
+ */
+public class ManagedForm implements IManagedForm {
+       private Object input;
+
+       private ScrolledComposite form;
+
+       private FormToolkit toolkit;
+
+       private Object container;
+
+       private boolean ownsToolkit;
+
+       private boolean initialized;
+
+       private Vector parts = new Vector();
+
+       /**
+        * Creates a managed form in the provided parent. Form toolkit and widget
+        * will be created and owned by this object.
+        * 
+        * @param parent
+        *            the parent widget
+        */
+       public ManagedForm(Composite parent) {
+               toolkit = new FormToolkit(parent.getDisplay());
+               ownsToolkit = true;
+               form = toolkit.createScrolledForm(parent);
+               
+       }
+
+       /**
+        * Creates a managed form that will use the provided toolkit and
+        * 
+        * @param toolkit
+        * @param form
+        */
+       public ManagedForm(FormToolkit toolkit, ScrolledComposite form) {
+               this.form = form;
+               this.toolkit = toolkit;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#addPart(org.eclipse.ui.forms.IFormPart)
+        */
+       public void addPart(IFormPart part) {
+               parts.add(part);
+               part.initialize(this);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#removePart(org.eclipse.ui.forms.IFormPart)
+        */
+       public void removePart(IFormPart part) {
+               parts.remove(part);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#getParts()
+        */
+       public IFormPart[] getParts() {
+               return (IFormPart[]) parts.toArray(new IFormPart[parts.size()]);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#getToolkit()
+        */
+       public FormToolkit getToolkit() {
+               return toolkit;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#getForm()
+        */
+       public ScrolledComposite getForm() {
+               return form;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#reflow(boolean)
+        */
+       public void reflow(boolean changed) {
+//             form.reflow(changed);
+       }
+
+       /**
+        * A part can use this method to notify other parts that implement
+        * IPartSelectionListener about selection changes.
+        * 
+        * @param part
+        *            the part that broadcasts the selection
+        * @param selection
+        *            the selection in the part
+        * @see IPartSelectionListener
+        */
+       public void fireSelectionChanged(IFormPart part, ISelection selection) {
+               for (int i = 0; i < parts.size(); i++) {
+                       IFormPart cpart = (IFormPart) parts.get(i);
+                       if (part.equals(cpart))
+                               continue;
+//                     if (cpart instanceof IPartSelectionListener) {
+//                             ((IPartSelectionListener) cpart).selectionChanged(part,
+//                                             selection);
+//                     }
+               }
+       }
+
+       /**
+        * Initializes the form by looping through the managed parts and
+        * initializing them. Has no effect if already called once.
+        */
+       public void initialize() {
+               if (initialized)
+                       return;
+               for (int i = 0; i < parts.size(); i++) {
+                       IFormPart part = (IFormPart) parts.get(i);
+                       part.initialize(this);
+               }
+               initialized = true;
+       }
+
+       /**
+        * Disposes all the parts in this form.
+        */
+       public void dispose() {
+               for (int i = 0; i < parts.size(); i++) {
+                       IFormPart part = (IFormPart) parts.get(i);
+                       part.dispose();
+               }
+               if (ownsToolkit) {
+                       toolkit.dispose();
+               }
+       }
+
+       /**
+        * Refreshes the form by refreshes all the stale parts. Since 3.1, this
+        * method is performed on a UI thread when called from another thread so it
+        * is not needed to wrap the call in <code>Display.syncExec</code> or
+        * <code>asyncExec</code>.
+        */
+       public void refresh() {
+               Thread t = Thread.currentThread();
+               Thread dt = toolkit.getColors().getDisplay().getThread();
+               if (t.equals(dt))
+                       doRefresh();
+               else {
+                       toolkit.getColors().getDisplay().asyncExec(new Runnable() {
+                               public void run() {
+                                       doRefresh();
+                               }
+                       });
+               }
+       }
+
+       private void doRefresh() {
+               int nrefreshed = 0;
+               for (int i = 0; i < parts.size(); i++) {
+                       IFormPart part = (IFormPart) parts.get(i);
+                       if (part.isStale()) {
+                               part.refresh();
+                               nrefreshed++;
+                       }
+               }
+//             if (nrefreshed > 0)
+//                     form.reflow(true);
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#commit(boolean)
+        */
+       public void commit(boolean onSave) {
+               for (int i = 0; i < parts.size(); i++) {
+                       IFormPart part = (IFormPart) parts.get(i);
+                       if (part.isDirty())
+                               part.commit(onSave);
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#setInput(java.lang.Object)
+        */
+       public boolean setInput(Object input) {
+               boolean pageResult = false;
+
+               this.input = input;
+               for (int i = 0; i < parts.size(); i++) {
+                       IFormPart part = (IFormPart) parts.get(i);
+                       boolean result = part.setFormInput(input);
+                       if (result)
+                               pageResult = true;
+               }
+               return pageResult;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#getInput()
+        */
+       public Object getInput() {
+               return input;
+       }
+
+       /**
+        * Transfers the focus to the first form part.
+        */
+       public void setFocus() {
+               if (parts.size() > 0) {
+                       IFormPart part = (IFormPart) parts.get(0);
+                       part.setFocus();
+               }
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#isDirty()
+        */
+       public boolean isDirty() {
+               for (int i = 0; i < parts.size(); i++) {
+                       IFormPart part = (IFormPart) parts.get(i);
+                       if (part.isDirty())
+                               return true;
+               }
+               return false;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#isStale()
+        */
+       public boolean isStale() {
+               for (int i = 0; i < parts.size(); i++) {
+                       IFormPart part = (IFormPart) parts.get(i);
+                       if (part.isStale())
+                               return true;
+               }
+               return false;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#dirtyStateChanged()
+        */
+       public void dirtyStateChanged() {
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#staleStateChanged()
+        */
+       public void staleStateChanged() {
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#getContainer()
+        */
+       public Object getContainer() {
+               return container;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.eclipse.ui.forms.IManagedForm#setContainer(java.lang.Object)
+        */
+       public void setContainer(Object container) {
+               this.container = container;
+       }
+
+       /* (non-Javadoc)
+        * @see org.eclipse.ui.forms.IManagedForm#getMessageManager()
+        */
+//     public IMessageManager getMessageManager() {
+//             return form.getMessageManager();
+//     }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/editor/FormEditor.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/editor/FormEditor.java
new file mode 100644 (file)
index 0000000..484dae8
--- /dev/null
@@ -0,0 +1,85 @@
+package org.argeo.cms.ui.eclipse.forms.editor;
+
+import org.argeo.cms.ui.eclipse.forms.FormToolkit;
+import org.eclipse.jface.dialogs.IPageChangeProvider;
+
+/**
+ * This class forms a base of multi-page form editors that typically use one or
+ * more pages with forms and one page for raw source of the editor input.
+ * <p>
+ * Pages are added 'lazily' i.e. adding a page reserves a tab for it but does
+ * not cause the page control to be created. Page control is created when an
+ * attempt is made to select the page in question. This allows editors with
+ * several tabs and complex pages to open quickly.
+ * <p>
+ * Subclasses should extend this class and implement <code>addPages</code>
+ * method. One of the two <code>addPage</code> methods should be called to
+ * contribute pages to the editor. One adds complete (standalone) editors as
+ * nested tabs. These editors will be created right away and will be hooked so
+ * that key bindings, selection service etc. is compatible with the one for the
+ * standalone case. The other method adds classes that implement
+ * <code>IFormPage</code> interface. These pages will be created lazily and
+ * they will share the common key binding and selection service. Since 3.1,
+ * FormEditor is a page change provider. It allows listeners to attach to it and
+ * get notified when pages are changed. This new API in JFace allows dynamic
+ * help to update on page changes.
+ * 
+ * @since 1.0
+ */
+// RAP [if] As RAP is still using workbench 3.4, the implementation of
+// IPageChangeProvider is missing from MultiPageEditorPart. Remove this code
+// with the adoption of workbench > 3.5
+//public abstract class FormEditor extends MultiPageEditorPart  {
+public abstract class FormEditor  implements
+        IPageChangeProvider {
+       private FormToolkit formToolkit;
+       
+       
+public FormToolkit getToolkit() {
+               return formToolkit;
+       }
+
+public void editorDirtyStateChanged() {
+       
+}
+
+public FormPage getActivePageInstance() {
+       return null;
+}
+
+       // RAP [if] As RAP is still using workbench 3.4, the implementation of
+// IPageChangeProvider is missing from MultiPageEditorPart. Remove this code
+// with the adoption of workbench > 3.5
+//     private ListenerList pageListeners = new ListenerList();
+//     
+//    /*
+//     * (non-Javadoc)
+//     * 
+//     * @see org.eclipse.jface.dialogs.IPageChangeProvider#addPageChangedListener(org.eclipse.jface.dialogs.IPageChangedListener)
+//     */
+//    public void addPageChangedListener(IPageChangedListener listener) {
+//        pageListeners.add(listener);
+//    }
+//
+//    /*
+//     * (non-Javadoc)
+//     * 
+//     * @see org.eclipse.jface.dialogs.IPageChangeProvider#removePageChangedListener(org.eclipse.jface.dialogs.IPageChangedListener)
+//     */
+//    public void removePageChangedListener(IPageChangedListener listener) {
+//        pageListeners.remove(listener);
+//    }
+//    
+//     private void firePageChanged(final PageChangedEvent event) {
+//        Object[] listeners = pageListeners.getListeners();
+//        for (int i = 0; i < listeners.length; ++i) {
+//            final IPageChangedListener l = (IPageChangedListener) listeners[i];
+//            SafeRunnable.run(new SafeRunnable() {
+//                public void run() {
+//                    l.pageChanged(event);
+//                }
+//            });
+//        }
+//    }
+// RAPEND [if]
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/editor/FormPage.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/editor/FormPage.java
new file mode 100644 (file)
index 0000000..a788412
--- /dev/null
@@ -0,0 +1,276 @@
+package org.argeo.cms.ui.eclipse.forms.editor;
+import org.argeo.cms.ui.eclipse.forms.IManagedForm;
+import org.argeo.cms.ui.eclipse.forms.ManagedForm;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+/**
+ * A base class that all pages that should be added to FormEditor must subclass.
+ * Form page has an instance of PageForm that extends managed form. Subclasses
+ * should override method 'createFormContent(ManagedForm)' to fill the form with
+ * content. Note that page itself can be loaded lazily (on first open).
+ * Consequently, the call to create the form content can come after the editor
+ * has been opened for a while (in fact, it is possible to open and close the
+ * editor and never create the form because no attempt has been made to show the
+ * page).
+ * 
+ * @since 1.0
+ */
+public class FormPage implements IFormPage {
+       private FormEditor editor;
+       private PageForm mform;
+       private int index;
+       private String id;
+       
+       private String partName;
+       
+       
+       
+       public void setPartName(String partName) {
+               this.partName = partName;
+       }
+       private static class PageForm extends ManagedForm {
+               public PageForm(FormPage page, ScrolledComposite form) {
+                       super(page.getEditor().getToolkit(), form);
+                       setContainer(page);
+               }
+               
+               public FormPage getPage() {
+                       return (FormPage)getContainer();
+               }
+               public void dirtyStateChanged() {
+                       getPage().getEditor().editorDirtyStateChanged();
+               }
+               public void staleStateChanged() {
+                       if (getPage().isActive())
+                               refresh();
+               }
+       }
+       /**
+        * A constructor that creates the page and initializes it with the editor.
+        * 
+        * @param editor
+        *            the parent editor
+        * @param id
+        *            the unique identifier
+        * @param title
+        *            the page title
+        */
+       public FormPage(FormEditor editor, String id, String title) {
+               this(id, title);
+               initialize(editor);
+       }
+       /**
+        * The constructor. The parent editor need to be passed in the
+        * <code>initialize</code> method if this constructor is used.
+        * 
+        * @param id
+        *            a unique page identifier
+        * @param title
+        *            a user-friendly page title
+        */
+       public FormPage(String id, String title) {
+               this.id = id;
+               setPartName(title);
+       }
+       /**
+        * Initializes the form page.
+        * 
+        * @see IEditorPart#init
+        */
+//     public void init(IEditorSite site, IEditorInput input) {
+//             setSite(site);
+//             setInput(input);
+//     }
+       /**
+        * Primes the form page with the parent editor instance.
+        * 
+        * @param editor
+        *            the parent editor
+        */
+       public void initialize(FormEditor editor) {
+               this.editor = editor;
+       }
+       /**
+        * Returns the parent editor.
+        * 
+        * @return parent editor instance
+        */
+       public FormEditor getEditor() {
+               return editor;
+       }
+       /**
+        * Returns the managed form owned by this page.
+        * 
+        * @return the managed form
+        */
+       public IManagedForm getManagedForm() {
+               return mform;
+       }
+       /**
+        * Implements the required method by refreshing the form when set active.
+        * Subclasses must call super when overriding this method.
+        */
+       public void setActive(boolean active) {
+               if (active) {
+                       // We are switching to this page - refresh it
+                       // if needed.
+                       if (mform != null)
+                               mform.refresh();
+               }
+       }
+       /**
+        * Tests if the page is active by asking the parent editor if this page is
+        * the currently active page.
+        * 
+        * @return <code>true</code> if the page is currently active,
+        *         <code>false</code> otherwise.
+        */
+       public boolean isActive() {
+               return this.equals(editor.getActivePageInstance());
+       }
+       /**
+        * Creates the part control by creating the managed form using the parent
+        * editor's toolkit. Subclasses should override
+        * <code>createFormContent(IManagedForm)</code> to populate the form with
+        * content.
+        * 
+        * @param parent
+        *            the page parent composite
+        */
+       public void createPartControl(Composite parent) {
+               ScrolledComposite form = editor.getToolkit().createScrolledForm(parent);
+               mform = new PageForm(this, form);
+               BusyIndicator.showWhile(parent.getDisplay(), new Runnable() {
+                       public void run() {
+                               createFormContent(mform);
+                       }
+               });
+       }
+       /**
+        * Subclasses should override this method to create content in the form
+        * hosted in this page.
+        * 
+        * @param managedForm
+        *            the form hosted in this page.
+        */
+       protected void createFormContent(IManagedForm managedForm) {
+       }
+       /**
+        * Returns the form page control.
+        * 
+        * @return managed form's control
+        */
+       public Control getPartControl() {
+               return mform != null ? mform.getForm() : null;
+       }
+       /**
+        * Disposes the managed form.
+        */
+       public void dispose() {
+               if (mform != null)
+                       mform.dispose();
+       }
+       /**
+        * Returns the unique identifier that can be used to reference this page.
+        * 
+        * @return the unique page identifier
+        */
+       public String getId() {
+               return id;
+       }
+       /**
+        * Returns <code>null</code>- form page has no title image. Subclasses
+        * may override.
+        * 
+        * @return <code>null</code>
+        */
+       public Image getTitleImage() {
+               return null;
+       }
+       /**
+        * Sets the focus by delegating to the managed form.
+        */
+       public void setFocus() {
+               if (mform != null)
+                       mform.setFocus();
+       }
+       /**
+        * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
+        */
+//     public void doSave(IProgressMonitor monitor) {
+//             if (mform != null)
+//                     mform.commit(true);
+//     }
+       /**
+        * @see org.eclipse.ui.ISaveablePart#doSaveAs()
+        */
+       public void doSaveAs() {
+       }
+       /**
+        * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
+        */
+       public boolean isSaveAsAllowed() {
+               return false;
+       }
+       /**
+        * Implemented by testing if the managed form is dirty.
+        * 
+        * @return <code>true</code> if the managed form is dirty,
+        *         <code>false</code> otherwise.
+        * 
+        * @see org.eclipse.ui.ISaveablePart#isDirty()
+        */
+       public boolean isDirty() {
+               return mform != null ? mform.isDirty() : false;
+       }
+       /**
+        * Preserves the page index.
+        * 
+        * @param index
+        *            the assigned page index
+        */
+       public void setIndex(int index) {
+               this.index = index;
+       }
+       /**
+        * Returns the saved page index.
+        * 
+        * @return the page index
+        */
+       public int getIndex() {
+               return index;
+       }
+       /**
+        * Form pages are not editors.
+        * 
+        * @return <code>false</code>
+        */
+       public boolean isEditor() {
+               return false;
+       }
+       /**
+        * Attempts to select and reveal the given object by passing the request to
+        * the managed form.
+        * 
+        * @param object
+        *            the object to select and reveal in the page if possible.
+        * @return <code>true</code> if the page has been successfully selected
+        *         and revealed by one of the managed form parts, <code>false</code>
+        *         otherwise.
+        */
+       public boolean selectReveal(Object object) {
+               if (mform != null)
+                       return mform.setInput(object);
+               return false;
+       }
+       /**
+        * By default, editor will be allowed to flip the page.
+        * @return <code>true</code>
+        */
+       public boolean canLeaveThePage() {
+               return true;
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/editor/IFormPage.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/eclipse/forms/editor/IFormPage.java
new file mode 100644 (file)
index 0000000..eb08cb5
--- /dev/null
@@ -0,0 +1,119 @@
+package org.argeo.cms.ui.eclipse.forms.editor;
+import org.argeo.cms.ui.eclipse.forms.IManagedForm;
+import org.eclipse.swt.widgets.Control;
+/**
+ * Interface that all GUI pages need to implement in order
+ * to be added to FormEditor part. The interface makes 
+ * several assumptions:
+ * <ul>
+ * <li>The form page has a managed form</li>
+ * <li>The form page has a unique id</li>
+ * <li>The form page can be GUI but can also wrap a complete
+ * editor class (in that case, it should return <code>true</code>
+ * from <code>isEditor()</code> method).</li>
+ * <li>The form page is lazy i.e. understands that 
+ * its part control will be created at the last possible
+ * moment.</li>.
+ * </ul>
+ * <p>Existing editors can be wrapped by implementing
+ * this interface. In this case, 'isEditor' should return <code>true</code>.
+ * A common editor to wrap in <code>TextEditor</code> that is
+ * often added to show the raw source code of the file open into
+ * the multi-page editor.
+ * 
+ * @since 1.0
+ */
+public interface IFormPage {
+       /**
+        * @param editor
+        *            the form editor that this page belongs to
+        */
+       void initialize(FormEditor editor);
+       /**
+        * Returns the editor this page belongs to.
+        * 
+        * @return the form editor
+        */
+       FormEditor getEditor();
+       /**
+        * Returns the managed form of this page, unless this is a source page.
+        * 
+        * @return the managed form or <samp>null </samp> if this is a source page.
+        */
+       IManagedForm getManagedForm();
+       /**
+        * Indicates whether the page has become the active in the editor. Classes
+        * that implement this interface may use this method to commit the page (on
+        * <code>false</code>) or lazily create and/or populate the content on
+        * <code>true</code>.
+        * 
+        * @param active
+        *            <code>true</code> if page should be visible, <code>false</code>
+        *            otherwise.
+        */
+       void setActive(boolean active);
+       /**
+        * Returns <samp>true </samp> if page is currently active, false if not.
+        * 
+        * @return <samp>true </samp> for active page.
+        */
+       boolean isActive();
+       /**
+        * Tests if the content of the page is in a state that allows the
+        * editor to flip to another page. Typically, pages that contain
+        * raw source with syntax errors should not allow editors to 
+        * leave them until errors are corrected.
+        * @return <code>true</code> if the editor can flip to another page,
+        * <code>false</code> otherwise.
+        */
+       boolean canLeaveThePage();
+       /**
+        * Returns the control associated with this page.
+        * 
+        * @return the control of this page if created or <samp>null </samp> if the
+        *         page has not been shown yet.
+        */
+       Control getPartControl();
+       /**
+        * Page must have a unique id that can be used to show it without knowing
+        * its relative position in the editor.
+        * 
+        * @return the unique page identifier
+        */
+       String getId();
+       /**
+        * Returns the position of the page in the editor.
+        * 
+        * @return the zero-based index of the page in the editor.
+        */
+       int getIndex();
+       /**
+        * Sets the position of the page in the editor.
+        * 
+        * @param index
+        *            the zero-based index of the page in the editor.
+        */
+       void setIndex(int index);
+       /**
+        * Tests whether this page wraps a complete editor that
+        * can be registered on its own, or represents a page
+        * that cannot exist outside the multi-page editor context.
+        * 
+        * @return <samp>true </samp> if the page wraps an editor,
+        *         <samp>false </samp> if this is a form page.
+        */
+       boolean isEditor();
+       /**
+        * A hint to bring the provided object into focus. If the object is in a
+        * tree or table control, select it. If it is shown on a scrollable page,
+        * ensure that it is visible. If the object is not presented in 
+        * the page, <code>false</code> should be returned to allow another
+        * page to try.
+        * 
+        * @param object
+        *            object to select and reveal
+        * @return <code>true</code> if the request was successful, <code>false</code>
+        *         otherwise.
+        */
+       boolean selectReveal(Object object);
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/EditableLink.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/EditableLink.java
new file mode 100644 (file)
index 0000000..3c1e8cd
--- /dev/null
@@ -0,0 +1,75 @@
+package org.argeo.cms.ui.forms;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.SwtEditablePart;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Editable String that displays a browsable link when read-only */
+public class EditableLink extends EditablePropertyString implements
+               SwtEditablePart {
+       private static final long serialVersionUID = 5055000749992803591L;
+
+       private String type;
+       private String message;
+       private boolean readOnly;
+
+       public EditableLink(Composite parent, int style, Node node,
+                       String propertyName, String type, String message)
+                       throws RepositoryException {
+               super(parent, style, node, propertyName, message);
+               this.message = message;
+               this.type = type;
+
+               readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
+               if (node.hasProperty(propertyName)) {
+                       this.setStyle(FormStyle.propertyText.style());
+                       this.setText(node.getProperty(propertyName).getString());
+               } else {
+                       this.setStyle(FormStyle.propertyMessage.style());
+                       this.setText("");
+               }
+       }
+
+       public void setText(String text) {
+               Control child = getControl();
+               if (child instanceof Label) {
+                       Label lbl = (Label) child;
+                       if (EclipseUiUtils.isEmpty(text))
+                               lbl.setText(message);
+                       else if (readOnly)
+                               setLinkValue(lbl, text);
+                       else
+                               // if canEdit() we put only the value with no link
+                               // to avoid glitches of the edition life cycle
+                               lbl.setText(text);
+               } else if (child instanceof Text) {
+                       Text txt = (Text) child;
+                       if (EclipseUiUtils.isEmpty(text)) {
+                               txt.setText("");
+                               txt.setMessage(message);
+                       } else
+                               txt.setText(text);
+               }
+       }
+
+       private void setLinkValue(Label lbl, String text) {
+               if (FormStyle.email.style().equals(type))
+                       lbl.setText(FormUtils.getMailLink(text));
+               else if (FormStyle.phone.style().equals(type))
+                       lbl.setText(FormUtils.getPhoneLink(text));
+               else if (FormStyle.website.style().equals(type))
+                       lbl.setText(FormUtils.getUrlLink(text));
+               else if (FormStyle.facebook.style().equals(type)
+                               || FormStyle.instagram.style().equals(type)
+                               || FormStyle.linkedIn.style().equals(type)
+                               || FormStyle.twitter.style().equals(type))
+                       lbl.setText(FormUtils.getUrlLink(text));
+       }
+}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/EditableMultiStringProperty.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/EditableMultiStringProperty.java
new file mode 100644 (file)
index 0000000..ff82700
--- /dev/null
@@ -0,0 +1,261 @@
+package org.argeo.cms.ui.forms;
+
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.SwtEditablePart;
+import org.argeo.cms.ui.widgets.StyledControl;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Display, add or remove values from a list in a CMS context */
+public class EditableMultiStringProperty extends StyledControl implements SwtEditablePart {
+       private static final long serialVersionUID = -7044614381252178595L;
+
+       private String propertyName;
+       private String message;
+       // TODO implement the ability to provide a list of possible values
+//     private String[] possibleValues;
+       private boolean canEdit;
+       private SelectionListener removeValueSL;
+       private List<String> values;
+
+       // TODO manage within the CSS
+       private int rowSpacing = 5;
+       private int rowMarging = 0;
+       private int oneValueMargingRight = 5;
+       private int btnWidth = 16;
+       private int btnHeight = 16;
+       private int btnHorizontalIndent = 3;
+
+       public EditableMultiStringProperty(Composite parent, int style, Node node, String propertyName, List<String> values,
+                       String[] possibleValues, String addValueMsg, SelectionListener removeValueSelectionListener)
+                       throws RepositoryException {
+               super(parent, style, node, true);
+
+               this.propertyName = propertyName;
+               this.values = values;
+//             this.possibleValues = new String[] { "Un", "Deux", "Trois" };
+               this.message = addValueMsg;
+               this.canEdit = removeValueSelectionListener != null;
+               this.removeValueSL = removeValueSelectionListener;
+       }
+
+       public List<String> getValues() {
+               return values;
+       }
+
+       public void setValues(List<String> values) {
+               this.values = values;
+       }
+
+       // Row layout items do not need explicit layout data
+       protected void setControlLayoutData(Control control) {
+       }
+
+       /** To be overridden */
+       protected void setContainerLayoutData(Composite composite) {
+               composite.setLayoutData(CmsSwtUtils.fillWidth());
+       }
+
+       @Override
+       public Control getControl() {
+               return super.getControl();
+       }
+
+       @Override
+       protected Control createControl(Composite box, String style) {
+               Composite row = new Composite(box, SWT.NO_FOCUS);
+               row.setLayoutData(EclipseUiUtils.fillAll());
+
+               RowLayout rl = new RowLayout(SWT.HORIZONTAL);
+               rl.wrap = true;
+               rl.spacing = rowSpacing;
+               rl.marginRight = rl.marginLeft = rl.marginBottom = rl.marginTop = rowMarging;
+               row.setLayout(rl);
+
+               if (values != null) {
+                       for (final String value : values) {
+                               if (canEdit)
+                                       createRemovableValue(row, SWT.SINGLE, value);
+                               else
+                                       createValueLabel(row, SWT.SINGLE, value);
+                       }
+               }
+
+               if (!canEdit)
+                       return row;
+               else if (isEditing())
+                       return createText(row, style);
+               else
+                       return createLabel(row, style);
+       }
+
+       /**
+        * Override to provide specific layout for the existing values, typically adding
+        * a pound (#) char for tags or anchor info for browsable links. We assume the
+        * parent composite already has a layout and it is the caller responsibility to
+        * apply corresponding layout data
+        */
+       protected Label createValueLabel(Composite parent, int style, String value) {
+               Label label = new Label(parent, style);
+               label.setText("#" + value);
+               CmsSwtUtils.markup(label);
+               CmsSwtUtils.style(label, FormStyle.propertyText.style());
+               return label;
+       }
+
+       private Composite createRemovableValue(Composite parent, int style, String value) {
+               Composite valCmp = new Composite(parent, SWT.NO_FOCUS);
+               GridLayout gl = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false));
+               gl.marginRight = oneValueMargingRight;
+               valCmp.setLayout(gl);
+
+               createValueLabel(valCmp, SWT.WRAP, value);
+
+               Button deleteBtn = new Button(valCmp, SWT.FLAT);
+               deleteBtn.setData(FormConstants.LINKED_VALUE, value);
+               deleteBtn.addSelectionListener(removeValueSL);
+               CmsSwtUtils.style(deleteBtn, FormStyle.delete.style() + FormStyle.BUTTON_SUFFIX);
+               GridData gd = new GridData();
+               gd.heightHint = btnHeight;
+               gd.widthHint = btnWidth;
+               gd.horizontalIndent = btnHorizontalIndent;
+               deleteBtn.setLayoutData(gd);
+
+               return valCmp;
+       }
+
+       protected Text createText(Composite box, String style) {
+               final Text text = new Text(box, getStyle());
+               // The "add new value" text is not meant to change, so we can set it on
+               // creation
+               text.setMessage(message);
+               CmsSwtUtils.style(text, style);
+               text.setFocus();
+
+               text.addTraverseListener(new TraverseListener() {
+                       private static final long serialVersionUID = 1L;
+
+                       public void keyTraversed(TraverseEvent e) {
+                               if (e.keyCode == SWT.CR) {
+                                       addValue(text);
+                                       e.doit = false;
+                               }
+                       }
+               });
+
+               // The OK button does not work with the focusOut listener
+               // because focus out is called before the OK button is pressed
+
+               // // we must call layout() now so that the row data can compute the
+               // height
+               // // of the other controls.
+               // text.getParent().layout();
+               // int height = text.getSize().y;
+               //
+               // Button okBtn = new Button(box, SWT.BORDER | SWT.PUSH | SWT.BOTTOM);
+               // okBtn.setText("OK");
+               // RowData rd = new RowData(SWT.DEFAULT, height - 2);
+               // okBtn.setLayoutData(rd);
+               //
+               // okBtn.addSelectionListener(new SelectionAdapter() {
+               // private static final long serialVersionUID = 2780819012423622369L;
+               //
+               // @Override
+               // public void widgetSelected(SelectionEvent e) {
+               // addValue(text);
+               // }
+               // });
+
+               return text;
+       }
+
+       /** Performs the real addition, overwrite to make further sanity checks */
+       protected void addValue(Text text) {
+               String value = text.getText();
+               String errMsg = null;
+
+               if (EclipseUiUtils.isEmpty(value))
+                       return;
+
+               if (values.contains(value))
+                       errMsg = "Dupplicated value: " + value + ", please correct and try again";
+               if (errMsg != null)
+                       MessageDialog.openError(this.getShell(), "Addition not allowed", errMsg);
+               else {
+                       values.add(value);
+                       Composite newCmp = createRemovableValue(text.getParent(), SWT.SINGLE, value);
+                       newCmp.moveAbove(text);
+                       text.setText("");
+                       newCmp.getParent().layout();
+               }
+       }
+
+       protected Label createLabel(Composite box, String style) {
+               if (canEdit) {
+                       Label lbl = new Label(box, getStyle());
+                       lbl.setText(message);
+                       CmsSwtUtils.style(lbl, style);
+                       CmsSwtUtils.markup(lbl);
+                       if (mouseListener != null)
+                               lbl.addMouseListener(mouseListener);
+                       return lbl;
+               }
+               return null;
+       }
+
+       protected void clear(boolean deep) {
+               Control child = getControl();
+               if (deep)
+                       super.clear(deep);
+               else {
+                       child.getParent().dispose();
+               }
+       }
+
+       public void setText(String text) {
+               Control child = getControl();
+               if (child instanceof Label) {
+                       Label lbl = (Label) child;
+                       if (canEdit)
+                               lbl.setText(text);
+                       else
+                               lbl.setText("");
+               } else if (child instanceof Text) {
+                       Text txt = (Text) child;
+                       txt.setText(text);
+               }
+       }
+
+       public synchronized void startEditing() {
+               CmsSwtUtils.style(getControl(), FormStyle.propertyText.style());
+//             getControl().setData(STYLE, FormStyle.propertyText.style());
+               super.startEditing();
+       }
+
+       public synchronized void stopEditing() {
+               CmsSwtUtils.style(getControl(), FormStyle.propertyMessage.style());
+//             getControl().setData(STYLE, FormStyle.propertyMessage.style());
+               super.stopEditing();
+       }
+
+       public String getPropertyName() {
+               return propertyName;
+       }
+}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/EditablePropertyDate.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/EditablePropertyDate.java
new file mode 100644 (file)
index 0000000..641f916
--- /dev/null
@@ -0,0 +1,298 @@
+package org.argeo.cms.ui.forms;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.SwtEditablePart;
+import org.argeo.cms.ui.widgets.StyledControl;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.DateTime;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/** CMS form part to display and edit a date */
+public class EditablePropertyDate extends StyledControl implements SwtEditablePart {
+       private static final long serialVersionUID = 2500215515778162468L;
+
+       // Context
+       private String propertyName;
+       private String message;
+       private DateFormat dateFormat;
+
+       // UI Objects
+       private Text dateTxt;
+       private Button openCalBtn;
+
+       // TODO manage within the CSS
+       private int fieldBtnSpacing = 5;
+
+       /**
+        * 
+        * @param parent
+        * @param style
+        * @param node
+        * @param propertyName
+        * @param message
+        * @param dateFormat   provide a {@link DateFormat} as contract to be able to
+        *                     read/write dates as strings
+        * @throws RepositoryException
+        */
+       public EditablePropertyDate(Composite parent, int style, Node node, String propertyName, String message,
+                       DateFormat dateFormat) throws RepositoryException {
+               super(parent, style, node, false);
+
+               this.propertyName = propertyName;
+               this.message = message;
+               this.dateFormat = dateFormat;
+
+               if (node.hasProperty(propertyName)) {
+                       this.setStyle(FormStyle.propertyText.style());
+                       this.setText(dateFormat.format(node.getProperty(propertyName).getDate().getTime()));
+               } else {
+                       this.setStyle(FormStyle.propertyMessage.style());
+                       this.setText(message);
+               }
+       }
+
+       public void setText(String text) {
+               Control child = getControl();
+               if (child instanceof Label) {
+                       Label lbl = (Label) child;
+                       if (EclipseUiUtils.isEmpty(text))
+                               lbl.setText(message);
+                       else
+                               lbl.setText(text);
+               } else if (child instanceof Text) {
+                       Text txt = (Text) child;
+                       if (EclipseUiUtils.isEmpty(text)) {
+                               txt.setText("");
+                       } else
+                               txt.setText(text);
+               }
+       }
+
+       public synchronized void startEditing() {
+               // if (dateTxt != null && !dateTxt.isDisposed())
+               CmsSwtUtils.style(getControl(), FormStyle.propertyText);
+//             getControl().setData(STYLE, FormStyle.propertyText.style());
+               super.startEditing();
+       }
+
+       public synchronized void stopEditing() {
+               if (EclipseUiUtils.isEmpty(dateTxt.getText()))
+                       CmsSwtUtils.style(getControl(), FormStyle.propertyMessage);
+//                     getControl().setData(STYLE, FormStyle.propertyMessage.style());
+               else
+                       CmsSwtUtils.style(getControl(), FormStyle.propertyText);
+//             getControl().setData(STYLE, FormStyle.propertyText.style());
+               super.stopEditing();
+       }
+
+       public String getPropertyName() {
+               return propertyName;
+       }
+
+       @Override
+       protected Control createControl(Composite box, String style) {
+               if (isEditing()) {
+                       return createCustomEditableControl(box, style);
+               } else
+                       return createLabel(box, style);
+       }
+
+       protected Label createLabel(Composite box, String style) {
+               Label lbl = new Label(box, getStyle() | SWT.WRAP);
+               lbl.setLayoutData(CmsSwtUtils.fillWidth());
+               CmsSwtUtils.style(lbl, style);
+               CmsSwtUtils.markup(lbl);
+               if (mouseListener != null)
+                       lbl.addMouseListener(mouseListener);
+               return lbl;
+       }
+
+       private Control createCustomEditableControl(Composite box, String style) {
+               box.setLayoutData(CmsSwtUtils.fillWidth());
+               Composite dateComposite = new Composite(box, SWT.NONE);
+               GridLayout gl = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false));
+               gl.horizontalSpacing = fieldBtnSpacing;
+               dateComposite.setLayout(gl);
+               dateTxt = new Text(dateComposite, SWT.BORDER);
+               CmsSwtUtils.style(dateTxt, style);
+               dateTxt.setLayoutData(new GridData(120, SWT.DEFAULT));
+               dateTxt.setToolTipText(
+                               "Enter a date with form \"" + FormUtils.DEFAULT_SHORT_DATE_FORMAT + "\" or use the calendar");
+               openCalBtn = new Button(dateComposite, SWT.FLAT);
+               CmsSwtUtils.style(openCalBtn, FormStyle.calendar.style() + FormStyle.BUTTON_SUFFIX);
+               GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+               gd.heightHint = 17;
+               openCalBtn.setLayoutData(gd);
+               // openCalBtn.setImage(PeopleRapImages.CALENDAR_BTN);
+
+               openCalBtn.addSelectionListener(new SelectionAdapter() {
+                       private static final long serialVersionUID = 1L;
+
+                       public void widgetSelected(SelectionEvent event) {
+                               CalendarPopup popup = new CalendarPopup(dateTxt);
+                               popup.open();
+                       }
+               });
+
+               // dateTxt.addFocusListener(new FocusListener() {
+               // private static final long serialVersionUID = 1L;
+               //
+               // @Override
+               // public void focusLost(FocusEvent event) {
+               // String newVal = dateTxt.getText();
+               // // Enable reset of the field
+               // if (FormUtils.notNull(newVal))
+               // calendar = null;
+               // else {
+               // try {
+               // Calendar newCal = parseDate(newVal);
+               // // DateText.this.setText(newCal);
+               // calendar = newCal;
+               // } catch (ParseException pe) {
+               // // Silent. Manage error popup?
+               // if (calendar != null)
+               // EditablePropertyDate.this.setText(calendar);
+               // }
+               // }
+               // }
+               //
+               // @Override
+               // public void focusGained(FocusEvent event) {
+               // }
+               // });
+               return dateTxt;
+       }
+
+       protected void clear(boolean deep) {
+               Control child = getControl();
+               if (deep || child instanceof Label)
+                       super.clear(deep);
+               else {
+                       child.getParent().dispose();
+               }
+       }
+
+       /** Enable setting a custom tooltip on the underlying text */
+       @Deprecated
+       public void setToolTipText(String toolTipText) {
+               dateTxt.setToolTipText(toolTipText);
+       }
+
+       @Deprecated
+       /** Enable setting a custom message on the underlying text */
+       public void setMessage(String message) {
+               dateTxt.setMessage(message);
+       }
+
+       @Deprecated
+       public void setText(Calendar cal) {
+               String newValueStr = "";
+               if (cal != null)
+                       newValueStr = dateFormat.format(cal.getTime());
+               if (!newValueStr.equals(dateTxt.getText()))
+                       dateTxt.setText(newValueStr);
+       }
+
+       // UTILITIES TO MANAGE THE CALENDAR POPUP
+       // TODO manage the popup shell in a cleaner way
+       private class CalendarPopup extends Shell {
+               private static final long serialVersionUID = 1L;
+               private DateTime dateTimeCtl;
+
+               public CalendarPopup(Control source) {
+                       super(source.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+                       populate();
+                       // Add border and shadow style
+                       CmsSwtUtils.markup(CalendarPopup.this);
+                       CmsSwtUtils.style(CalendarPopup.this, FormStyle.popupCalendar.style());
+                       pack();
+                       layout();
+                       setLocation(source.toDisplay((source.getLocation().x - 2), (source.getSize().y) + 3));
+
+                       addShellListener(new ShellAdapter() {
+                               private static final long serialVersionUID = 5178980294808435833L;
+
+                               @Override
+                               public void shellDeactivated(ShellEvent e) {
+                                       close();
+                                       dispose();
+                               }
+                       });
+                       open();
+               }
+
+               private void setProperty() {
+                       // Direct set does not seems to work. investigate
+                       // cal.set(dateTimeCtl.getYear(), dateTimeCtl.getMonth(),
+                       // dateTimeCtl.getDay(), 12, 0);
+                       Calendar cal = new GregorianCalendar();
+                       cal.set(Calendar.YEAR, dateTimeCtl.getYear());
+                       cal.set(Calendar.MONTH, dateTimeCtl.getMonth());
+                       cal.set(Calendar.DAY_OF_MONTH, dateTimeCtl.getDay());
+                       String dateStr = dateFormat.format(cal.getTime());
+                       dateTxt.setText(dateStr);
+               }
+
+               protected void populate() {
+                       setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+                       dateTimeCtl = new DateTime(this, SWT.CALENDAR);
+                       dateTimeCtl.setLayoutData(EclipseUiUtils.fillAll());
+
+                       Calendar calendar = FormUtils.parseDate(dateFormat, dateTxt.getText());
+
+                       if (calendar != null)
+                               dateTimeCtl.setDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
+                                               calendar.get(Calendar.DAY_OF_MONTH));
+
+                       dateTimeCtl.addSelectionListener(new SelectionAdapter() {
+                               private static final long serialVersionUID = -8414377364434281112L;
+
+                               @Override
+                               public void widgetSelected(SelectionEvent e) {
+                                       setProperty();
+                               }
+                       });
+
+                       dateTimeCtl.addMouseListener(new MouseListener() {
+                               private static final long serialVersionUID = 1L;
+
+                               @Override
+                               public void mouseUp(MouseEvent e) {
+                               }
+
+                               @Override
+                               public void mouseDown(MouseEvent e) {
+                               }
+
+                               @Override
+                               public void mouseDoubleClick(MouseEvent e) {
+                                       setProperty();
+                                       close();
+                                       dispose();
+                               }
+                       });
+               }
+       }
+}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/EditablePropertyString.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/EditablePropertyString.java
new file mode 100644 (file)
index 0000000..f2575e1
--- /dev/null
@@ -0,0 +1,80 @@
+package org.argeo.cms.ui.forms;
+
+import static org.argeo.cms.ui.forms.FormStyle.propertyMessage;
+import static org.argeo.cms.ui.forms.FormStyle.propertyText;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.SwtEditablePart;
+import org.argeo.cms.ui.widgets.EditableText;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Editable String in a CMS context */
+public class EditablePropertyString extends EditableText implements SwtEditablePart {
+       private static final long serialVersionUID = 5055000749992803591L;
+
+       private String propertyName;
+       private String message;
+
+       // encode the '&' character in rap
+       private final static String AMPERSAND = "&#38;";
+       private final static String AMPERSAND_REGEX = "&(?![#a-zA-Z0-9]+;)";
+
+       public EditablePropertyString(Composite parent, int style, Node node, String propertyName, String message)
+                       throws RepositoryException {
+               super(parent, style, node, true);
+               //setUseTextAsLabel(true);
+               this.propertyName = propertyName;
+               this.message = message;
+
+               if (node.hasProperty(propertyName)) {
+                       this.setStyle(propertyText.style());
+                       this.setText(node.getProperty(propertyName).getString());
+               } else {
+                       this.setStyle(propertyMessage.style());
+                       this.setText(message + "  ");
+               }
+       }
+
+       public void setText(String text) {
+               Control child = getControl();
+               if (child instanceof Label) {
+                       Label lbl = (Label) child;
+                       if (EclipseUiUtils.isEmpty(text))
+                               lbl.setText(message + "  ");
+                       else
+                               // TODO enhance this
+                               lbl.setText(text.replaceAll(AMPERSAND_REGEX, AMPERSAND));
+               } else if (child instanceof Text) {
+                       Text txt = (Text) child;
+                       if (EclipseUiUtils.isEmpty(text)) {
+                               txt.setText("");
+                               txt.setMessage(message + " ");
+                       } else
+                               txt.setText(text.replaceAll("<br/>", "\n"));
+               }
+       }
+
+       public synchronized void startEditing() {
+               CmsSwtUtils.style(getControl(), FormStyle.propertyText);
+               super.startEditing();
+       }
+
+       public synchronized void stopEditing() {
+               if (EclipseUiUtils.isEmpty(((Text) getControl()).getText()))
+                       CmsSwtUtils.style(getControl(), FormStyle.propertyMessage);
+               else
+                       CmsSwtUtils.style(getControl(), FormStyle.propertyText);
+               super.stopEditing();
+       }
+
+       public String getPropertyName() {
+               return propertyName;
+       }
+}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormConstants.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormConstants.java
new file mode 100644 (file)
index 0000000..fe9f7e7
--- /dev/null
@@ -0,0 +1,7 @@
+package org.argeo.cms.ui.forms;
+
+/** Constants used in the various CMS Forms */
+public interface FormConstants {
+       // DATAKEYS
+       public final static String LINKED_VALUE = "LinkedValue";
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormEditorHeader.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormEditorHeader.java
new file mode 100644 (file)
index 0000000..a75c191
--- /dev/null
@@ -0,0 +1,114 @@
+package org.argeo.cms.ui.forms;
+
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.jcr.Node;
+
+import org.argeo.api.cms.ux.CmsEditable;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+
+/** Add life cycle management abilities to an editable form page */
+public class FormEditorHeader implements SelectionListener, Observer {
+       private static final long serialVersionUID = 7392898696542484282L;
+
+       // private final Node context;
+       private final CmsEditable cmsEditable;
+       private Button publishBtn;
+
+       // Should we provide here the ability to switch from read only to edition
+       // mode?
+       // private Button editBtn;
+       // private boolean readOnly;
+
+       // TODO add information about the current node status, typically if it is
+       // dirty or not
+
+       private Composite parent;
+       private Composite display;
+       private Object layoutData;
+
+       public FormEditorHeader(Composite parent, int style, Node context,
+                       CmsEditable cmsEditable) {
+               this.cmsEditable = cmsEditable;
+               this.parent = parent;
+               // readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
+               // this.context = context;
+               if (this.cmsEditable instanceof Observable)
+                       ((Observable) this.cmsEditable).addObserver(this);
+               refresh();
+       }
+
+       public void setLayoutData(Object layoutData) {
+               this.layoutData = layoutData;
+               if (display != null && !display.isDisposed())
+                       display.setLayoutData(layoutData);
+       }
+
+       protected void refresh() {
+               if (display != null && !display.isDisposed())
+                       display.dispose();
+
+               display = new Composite(parent, SWT.NONE);
+               display.setLayoutData(layoutData);
+
+               CmsSwtUtils.style(display, FormStyle.header.style());
+               display.setBackgroundMode(SWT.INHERIT_FORCE);
+
+               display.setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+               publishBtn = createSimpleBtn(display, getPublishButtonLabel());
+               display.moveAbove(null);
+               parent.layout();
+       }
+
+       private Button createSimpleBtn(Composite parent, String label) {
+               Button button = new Button(parent, SWT.FLAT | SWT.PUSH);
+               button.setText(label);
+               CmsSwtUtils.style(button, FormStyle.header.style());
+               button.addSelectionListener(this);
+               return button;
+       }
+
+       private String getPublishButtonLabel() {
+               // Rather check if the current node differs from what has been
+               // previously committed
+               // For the time being, we always reach here, the underlying CmsEditable
+               // is always editing.
+               if (cmsEditable.isEditing())
+                       return " Publish ";
+               else
+                       return " Edit ";
+       }
+
+       @Override
+       public void widgetSelected(SelectionEvent e) {
+               if (e.getSource() == publishBtn) {
+                       // For the time being, the underlying CmsEditable
+                       // is always editing when we reach this point
+                       if (cmsEditable.isEditing()) {
+                               // we always leave the node in a check outed state
+                               cmsEditable.stopEditing();
+                               cmsEditable.startEditing();
+                       } else {
+                               cmsEditable.startEditing();
+                       }
+               }
+       }
+
+       @Override
+       public void widgetDefaultSelected(SelectionEvent e) {
+       }
+
+       @Override
+       public void update(Observable o, Object arg) {
+               if (o == cmsEditable) {
+                       refresh();
+               }
+       }
+}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormPageViewer.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormPageViewer.java
new file mode 100644 (file)
index 0000000..1888055
--- /dev/null
@@ -0,0 +1,608 @@
+package org.argeo.cms.ui.forms;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.api.cms.ux.CmsEditable;
+import org.argeo.api.cms.ux.CmsImageManager;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.SwtEditablePart;
+import org.argeo.cms.ui.viewers.AbstractPageViewer;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.cms.ui.viewers.SectionPart;
+import org.argeo.cms.ui.widgets.EditableImage;
+import org.argeo.cms.ui.widgets.Img;
+import org.argeo.cms.ui.widgets.StyledControl;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.rap.fileupload.FileDetails;
+import org.eclipse.rap.fileupload.FileUploadEvent;
+import org.eclipse.rap.fileupload.FileUploadHandler;
+import org.eclipse.rap.fileupload.FileUploadListener;
+import org.eclipse.rap.fileupload.FileUploadReceiver;
+import org.eclipse.rap.rwt.service.ServerPushSession;
+import org.eclipse.rap.rwt.widgets.FileUpload;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Manage life cycle of a form page that is linked to a given node */
+public class FormPageViewer extends AbstractPageViewer {
+       private final static CmsLog log = CmsLog.getLog(FormPageViewer.class);
+       private static final long serialVersionUID = 5277789504209413500L;
+
+       private final Section mainSection;
+
+       // TODO manage within the CSS
+       private Integer labelColWidth = null;
+       private int rowLayoutHSpacing = 8;
+
+       // Context cached in the viewer
+       // The reference to translate from text to calendar and reverse
+       private DateFormat dateFormat = new SimpleDateFormat(FormUtils.DEFAULT_SHORT_DATE_FORMAT);
+       private CmsImageManager<Control, Node> imageManager;
+       private FileUploadListener fileUploadListener;
+
+       public FormPageViewer(Section mainSection, int style, CmsEditable cmsEditable) throws RepositoryException {
+               super(mainSection, style, cmsEditable);
+               this.mainSection = mainSection;
+
+               if (getCmsEditable().canEdit()) {
+                       fileUploadListener = new FUL();
+               }
+       }
+
+       @Override
+       protected void prepare(SwtEditablePart part, Object caretPosition) {
+               if (part instanceof Img) {
+                       ((Img) part).setFileUploadListener(fileUploadListener);
+               }
+       }
+
+       /** To be overridden.Save the edited part. */
+       protected void save(SwtEditablePart part) throws RepositoryException {
+               Node node = null;
+               if (part instanceof EditableMultiStringProperty) {
+                       EditableMultiStringProperty ept = (EditableMultiStringProperty) part;
+                       // SWT : View
+                       List<String> values = ept.getValues();
+                       // JCR : Model
+                       node = ept.getNode();
+                       String propName = ept.getPropertyName();
+                       if (values.isEmpty()) {
+                               if (node.hasProperty(propName))
+                                       node.getProperty(propName).remove();
+                       } else {
+                               node.setProperty(propName, values.toArray(new String[0]));
+                       }
+                       // => Viewer : Controller
+               } else if (part instanceof EditablePropertyString) {
+                       EditablePropertyString ept = (EditablePropertyString) part;
+                       // SWT : View
+                       String txt = ((Text) ept.getControl()).getText();
+                       // JCR : Model
+                       node = ept.getNode();
+                       String propName = ept.getPropertyName();
+                       if (EclipseUiUtils.isEmpty(txt)) {
+                               if (node.hasProperty(propName))
+                                       node.getProperty(propName).remove();
+                       } else {
+                               setPropertySilently(node, propName, txt);
+                               // node.setProperty(propName, txt);
+                       }
+                       // node.getSession().save();
+                       // => Viewer : Controller
+               } else if (part instanceof EditablePropertyDate) {
+                       EditablePropertyDate ept = (EditablePropertyDate) part;
+                       Calendar cal = FormUtils.parseDate(dateFormat, ((Text) ept.getControl()).getText());
+                       node = ept.getNode();
+                       String propName = ept.getPropertyName();
+                       if (cal == null) {
+                               if (node.hasProperty(propName))
+                                       node.getProperty(propName).remove();
+                       } else {
+                               node.setProperty(propName, cal);
+                       }
+                       // node.getSession().save();
+                       // => Viewer : Controller
+               }
+               // TODO: make this configurable, sometimes we do not want to save the
+               // current session at this stage
+               if (node != null && node.getSession().hasPendingChanges()) {
+                       JcrUtils.updateLastModified(node, true);
+                       node.getSession().save();
+               }
+       }
+
+       @Override
+       protected void updateContent(SwtEditablePart part) throws RepositoryException {
+               if (part instanceof EditableMultiStringProperty) {
+                       EditableMultiStringProperty ept = (EditableMultiStringProperty) part;
+                       // SWT : View
+                       Node node = ept.getNode();
+                       String propName = ept.getPropertyName();
+                       List<String> valStrings = new ArrayList<String>();
+                       if (node.hasProperty(propName)) {
+                               Value[] values = node.getProperty(propName).getValues();
+                               for (Value val : values)
+                                       valStrings.add(val.getString());
+                       }
+                       ept.setValues(valStrings);
+               } else if (part instanceof EditablePropertyString) {
+                       // || part instanceof EditableLink
+                       EditablePropertyString ept = (EditablePropertyString) part;
+                       // JCR : Model
+                       Node node = ept.getNode();
+                       String propName = ept.getPropertyName();
+                       if (node.hasProperty(propName)) {
+                               String value = node.getProperty(propName).getString();
+                               ept.setText(value);
+                       } else
+                               ept.setText("");
+                       // => Viewer : Controller
+               } else if (part instanceof EditablePropertyDate) {
+                       EditablePropertyDate ept = (EditablePropertyDate) part;
+                       // JCR : Model
+                       Node node = ept.getNode();
+                       String propName = ept.getPropertyName();
+                       if (node.hasProperty(propName))
+                               ept.setText(dateFormat.format(node.getProperty(propName).getDate().getTime()));
+                       else
+                               ept.setText("");
+               } else if (part instanceof SectionPart) {
+                       SectionPart sectionPart = (SectionPart) part;
+                       Node partNode = sectionPart.getNode();
+                       // use control AFTER setting style, since it may have been reset
+                       if (part instanceof EditableImage) {
+                               EditableImage editableImage = (EditableImage) part;
+                               imageManager().load(partNode, part.getControl(), editableImage.getPreferredImageSize());
+                       }
+               }
+       }
+
+       // FILE UPLOAD LISTENER
+       protected class FUL implements FileUploadListener {
+
+               public FUL() {
+               }
+
+               public void uploadProgress(FileUploadEvent event) {
+                       // TODO Monitor upload progress
+               }
+
+               public void uploadFailed(FileUploadEvent event) {
+                       throw new IllegalStateException("Upload failed " + event, event.getException());
+               }
+
+               public void uploadFinished(FileUploadEvent event) {
+                       for (FileDetails file : event.getFileDetails()) {
+                               if (log.isDebugEnabled())
+                                       log.debug("Received: " + file.getFileName());
+                       }
+                       mainSection.getDisplay().syncExec(new Runnable() {
+                               @Override
+                               public void run() {
+                                       saveEdit();
+                               }
+                       });
+                       FileUploadHandler uploadHandler = (FileUploadHandler) event.getSource();
+                       uploadHandler.dispose();
+               }
+       }
+
+       // FOCUS OUT LISTENER
+       protected FocusListener createFocusListener() {
+               return new FocusOutListener();
+       }
+
+       private class FocusOutListener implements FocusListener {
+               private static final long serialVersionUID = -6069205786732354186L;
+
+               @Override
+               public void focusLost(FocusEvent event) {
+                       saveEdit();
+               }
+
+               @Override
+               public void focusGained(FocusEvent event) {
+                       // does nothing;
+               }
+       }
+
+       // MOUSE LISTENER
+       @Override
+       protected MouseListener createMouseListener() {
+               return new ML();
+       }
+
+       private class ML extends MouseAdapter {
+               private static final long serialVersionUID = 8526890859876770905L;
+
+               @Override
+               public void mouseDoubleClick(MouseEvent e) {
+                       if (e.button == 1) {
+                               Control source = (Control) e.getSource();
+                               if (getCmsEditable().canEdit()) {
+                                       if (getCmsEditable().isEditing() && !(getEdited() instanceof Img)) {
+                                               if (source == mainSection)
+                                                       return;
+                                               SwtEditablePart part = findDataParent(source);
+                                               upload(part);
+                                       } else {
+                                               getCmsEditable().startEditing();
+                                       }
+                               }
+                       }
+               }
+
+               @Override
+               public void mouseDown(MouseEvent e) {
+                       if (getCmsEditable().isEditing()) {
+                               if (e.button == 1) {
+                                       Control source = (Control) e.getSource();
+                                       SwtEditablePart composite = findDataParent(source);
+                                       Point point = new Point(e.x, e.y);
+                                       if (!(composite instanceof Img))
+                                               edit(composite, source.toDisplay(point));
+                               } else if (e.button == 3) {
+                                       // EditablePart composite = findDataParent((Control) e
+                                       // .getSource());
+                                       // if (styledTools != null)
+                                       // styledTools.show(composite, new Point(e.x, e.y));
+                               }
+                       }
+               }
+
+               protected synchronized void upload(SwtEditablePart part) {
+                       if (part instanceof SectionPart) {
+                               if (part instanceof Img) {
+                                       if (getEdited() == part)
+                                               return;
+                                       edit(part, null);
+                                       layout(part.getControl());
+                               }
+                       }
+               }
+       }
+
+       @Override
+       public Control getControl() {
+               return mainSection;
+       }
+
+       protected CmsImageManager<Control, Node> imageManager() {
+               if (imageManager == null)
+                       imageManager = (CmsImageManager<Control, Node>) CmsSwtUtils.getCmsView(mainSection).getImageManager();
+               return imageManager;
+       }
+
+       // LOCAL UI HELPERS
+       protected Section createSectionIfNeeded(Composite body, Node node) throws RepositoryException {
+               Section section = null;
+               if (node != null) {
+                       section = new Section(body, SWT.NO_FOCUS, node);
+                       section.setLayoutData(CmsSwtUtils.fillWidth());
+                       section.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               }
+               return section;
+       }
+
+       protected void createSimpleLT(Composite bodyRow, Node node, String propName, String label, String msg)
+                       throws RepositoryException {
+               if (getCmsEditable().canEdit() || node.hasProperty(propName)) {
+                       createPropertyLbl(bodyRow, label);
+                       EditablePropertyString eps = new EditablePropertyString(bodyRow, SWT.WRAP | SWT.LEFT, node, propName, msg);
+                       eps.setMouseListener(getMouseListener());
+                       eps.setFocusListener(getFocusListener());
+                       eps.setLayoutData(CmsSwtUtils.fillWidth());
+               }
+       }
+
+       protected void createMultiStringLT(Composite bodyRow, Node node, String propName, String label, String msg)
+                       throws RepositoryException {
+               boolean canEdit = getCmsEditable().canEdit();
+               if (canEdit || node.hasProperty(propName)) {
+                       createPropertyLbl(bodyRow, label);
+
+                       List<String> valueStrings = new ArrayList<String>();
+
+                       if (node.hasProperty(propName)) {
+                               Value[] values = node.getProperty(propName).getValues();
+                               for (Value value : values)
+                                       valueStrings.add(value.getString());
+                       }
+
+                       // TODO use a drop down to display possible values to the end user
+                       EditableMultiStringProperty emsp = new EditableMultiStringProperty(bodyRow, SWT.SINGLE | SWT.LEAD, node,
+                                       propName, valueStrings, new String[] { "Implement this" }, msg,
+                                       canEdit ? getRemoveValueSelListener() : null);
+                       addListeners(emsp);
+                       // emsp.setMouseListener(getMouseListener());
+                       emsp.setStyle(FormStyle.propertyMessage.style());
+                       emsp.setLayoutData(CmsSwtUtils.fillWidth());
+               }
+       }
+
+       protected Label createPropertyLbl(Composite parent, String value) {
+               return createPropertyLbl(parent, value, SWT.NONE);
+       }
+
+       protected Label createPropertyLbl(Composite parent, String value, int vAlign) {
+               // boolean isSmall = CmsView.getCmsView(parent).getUxContext().isSmall();
+               Label label = new Label(parent, SWT.LEAD | SWT.WRAP);
+               label.setText(value + " ");
+               CmsSwtUtils.style(label, FormStyle.propertyLabel.style());
+               GridData gd = new GridData(SWT.LEAD, vAlign, false, false);
+               if (labelColWidth != null)
+                       gd.widthHint = labelColWidth;
+               label.setLayoutData(gd);
+               return label;
+       }
+
+       protected Label newStyledLabel(Composite parent, String style, String value) {
+               Label label = new Label(parent, SWT.NONE);
+               label.setText(value);
+               CmsSwtUtils.style(label, style);
+               return label;
+       }
+
+       protected Composite createRowLayoutComposite(Composite parent) throws RepositoryException {
+               Composite bodyRow = new Composite(parent, SWT.NO_FOCUS);
+               bodyRow.setLayoutData(CmsSwtUtils.fillWidth());
+               RowLayout rl = new RowLayout(SWT.WRAP);
+               rl.type = SWT.HORIZONTAL;
+               rl.spacing = rowLayoutHSpacing;
+               rl.marginHeight = rl.marginWidth = 0;
+               rl.marginTop = rl.marginBottom = rl.marginLeft = rl.marginRight = 0;
+               bodyRow.setLayout(rl);
+               return bodyRow;
+       }
+
+       protected Composite createAddImgComposite(final Section section, Composite parent, final Node parentNode)
+                       throws RepositoryException {
+
+               Composite body = new Composite(parent, SWT.NO_FOCUS);
+               body.setLayout(new GridLayout());
+
+               FormFileUploadReceiver receiver = new FormFileUploadReceiver(section, parentNode, null);
+               final FileUploadHandler currentUploadHandler = new FileUploadHandler(receiver);
+               if (fileUploadListener != null)
+                       currentUploadHandler.addUploadListener(fileUploadListener);
+
+               // Button creation
+               final FileUpload fileUpload = new FileUpload(body, SWT.BORDER);
+               fileUpload.setText("Import an image");
+               fileUpload.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+               fileUpload.addSelectionListener(new SelectionAdapter() {
+                       private static final long serialVersionUID = 4869523412991968759L;
+
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               ServerPushSession pushSession = new ServerPushSession();
+                               pushSession.start();
+                               String uploadURL = currentUploadHandler.getUploadUrl();
+                               fileUpload.submit(uploadURL);
+                       }
+               });
+
+               return body;
+       }
+
+       protected class FormFileUploadReceiver extends FileUploadReceiver {
+
+               private Node context;
+               private Section section;
+               private String name;
+
+               public FormFileUploadReceiver(Section section, Node context, String name) {
+                       this.context = context;
+                       this.section = section;
+                       this.name = name;
+               }
+
+               @Override
+               public void receive(InputStream stream, FileDetails details) throws IOException {
+
+                       if (name == null)
+                               name = details.getFileName();
+
+                       // TODO clean image name more carefully
+                       String cleanedName = name.replaceAll("[^a-zA-Z0-9-.]", "");
+                       // We add a unique prefix to workaround the cache issue: when
+                       // deleting and re-adding a new image with same name, the end user
+                       // browser will use the cache and the image will remain unchanged
+                       // for a while
+                       cleanedName = System.currentTimeMillis() % 100000 + "_" + cleanedName;
+
+                       imageManager().uploadImage(context, context, cleanedName, stream, details.getContentType());
+                       // TODO clean refresh strategy
+                       section.getDisplay().asyncExec(new Runnable() {
+                               @Override
+                               public void run() {
+                                       try {
+                                               FormPageViewer.this.refresh(section);
+                                               section.layout();
+                                               section.getParent().layout();
+                                       } catch (RepositoryException re) {
+                                               throw new JcrException("Unable to refresh " + "image section for " + context, re);
+                                       }
+                               }
+                       });
+               }
+       }
+
+       protected void addListeners(StyledControl control) {
+               control.setMouseListener(getMouseListener());
+               control.setFocusListener(getFocusListener());
+       }
+
+       protected Img createImgComposite(Composite parent, Node node, Point preferredSize) throws RepositoryException {
+               Img img = new Img(parent, SWT.NONE, node, new Cms2DSize(preferredSize.x, preferredSize.y)) {
+                       private static final long serialVersionUID = 1297900641952417540L;
+
+                       @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));
+                       }
+               };
+               img.setLayoutData(CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
+               updateContent(img);
+               addListeners(img);
+               return img;
+       }
+
+       protected Composite addDeleteAbility(final Section section, final Node sessionNode, int topWeight,
+                       int rightWeight) {
+               Composite comp = new Composite(section, SWT.NONE);
+               comp.setLayoutData(CmsSwtUtils.fillAll());
+               comp.setLayout(new FormLayout());
+
+               // The body to be populated
+               Composite body = new Composite(comp, SWT.NO_FOCUS);
+               body.setLayoutData(EclipseUiUtils.fillFormData());
+
+               if (getCmsEditable().canEdit()) {
+                       // the delete button
+                       Button deleteBtn = new Button(comp, SWT.FLAT);
+                       CmsSwtUtils.style(deleteBtn, FormStyle.deleteOverlay.style());
+                       FormData formData = new FormData();
+                       formData.right = new FormAttachment(rightWeight, 0);
+                       formData.top = new FormAttachment(topWeight, 0);
+                       deleteBtn.setLayoutData(formData);
+                       deleteBtn.moveAbove(body);
+
+                       deleteBtn.addSelectionListener(new SelectionAdapter() {
+                               private static final long serialVersionUID = 4304223543657238462L;
+
+                               @Override
+                               public void widgetSelected(SelectionEvent e) {
+                                       super.widgetSelected(e);
+                                       if (MessageDialog.openConfirm(section.getShell(), "Confirm deletion",
+                                                       "Are you really you want to remove this?")) {
+                                               Session session;
+                                               try {
+                                                       session = sessionNode.getSession();
+                                                       Section parSection = section.getParentSection();
+                                                       sessionNode.remove();
+                                                       session.save();
+                                                       refresh(parSection);
+                                                       layout(parSection);
+                                               } catch (RepositoryException re) {
+                                                       throw new JcrException("Unable to delete " + sessionNode, re);
+                                               }
+
+                                       }
+
+                               }
+                       });
+               }
+               return body;
+       }
+
+//     // LOCAL HELPERS FOR NODE MANAGEMENT
+//     private Node getOrCreateNode(Node parent, String nodeName, String nodeType) throws RepositoryException {
+//             Node node = null;
+//             if (getCmsEditable().canEdit() && !parent.hasNode(nodeName)) {
+//                     node = JcrUtils.mkdirs(parent, nodeName, nodeType);
+//                     parent.getSession().save();
+//             }
+//
+//             if (getCmsEditable().canEdit() || parent.hasNode(nodeName))
+//                     node = parent.getNode(nodeName);
+//
+//             return node;
+//     }
+
+       private SelectionListener getRemoveValueSelListener() {
+               return new SelectionAdapter() {
+                       private static final long serialVersionUID = 9022259089907445195L;
+
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               Object source = e.getSource();
+                               if (source instanceof Button) {
+                                       Button btn = (Button) source;
+                                       Object obj = btn.getData(FormConstants.LINKED_VALUE);
+                                       SwtEditablePart ep = findDataParent(btn);
+                                       if (ep != null && ep instanceof EditableMultiStringProperty) {
+                                               EditableMultiStringProperty emsp = (EditableMultiStringProperty) ep;
+                                               List<String> values = emsp.getValues();
+                                               if (values.contains(obj)) {
+                                                       values.remove(values.indexOf(obj));
+                                                       emsp.setValues(values);
+                                                       try {
+                                                               save(emsp);
+                                                               // TODO workaround to force refresh
+                                                               edit(emsp, 0);
+                                                               cancelEdit();
+                                                       } catch (RepositoryException e1) {
+                                                               throw new JcrException("Unable to remove value " + obj, e1);
+                                                       }
+                                                       layout(emsp);
+                                               }
+                                       }
+                               }
+                       }
+               };
+       }
+
+       protected void setPropertySilently(Node node, String propName, String value) throws RepositoryException {
+               try {
+                       // TODO Clean this:
+                       // Format strings to replace \n
+                       value = value.replaceAll("\n", "<br/>");
+                       // Do not make the update if validation fails
+                       try {
+                               MarkupValidatorCopy.getInstance().validate(value);
+                       } catch (Exception e) {
+                               log.warn("Cannot set [" + value + "] on prop " + propName + "of " + node
+                                               + ", String cannot be validated - " + e.getMessage());
+                               return;
+                       }
+                       // TODO check if the newly created property is of the correct type,
+                       // otherwise the property will be silently created with a STRING
+                       // property type.
+                       node.setProperty(propName, value);
+               } catch (ValueFormatException vfe) {
+                       log.warn("Cannot set [" + value + "] on prop " + propName + "of " + node + " - " + vfe.getMessage());
+               }
+       }
+}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormStyle.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormStyle.java
new file mode 100644 (file)
index 0000000..709ecd0
--- /dev/null
@@ -0,0 +1,29 @@
+package org.argeo.cms.ui.forms;
+
+import org.argeo.api.cms.ux.CmsStyle;
+
+/** Syles used */
+public enum FormStyle implements CmsStyle {
+       // Main
+       form, title,
+       // main part
+       header, headerBtn, headerCombo, section, sectionHeader,
+       // Property fields
+       propertyLabel, propertyText, propertyMessage, errorMessage,
+       // Date
+       popupCalendar,
+       // Buttons
+       starred, unstarred, starOverlay, editOverlay, deleteOverlay, updateOverlay, deleteOverlaySmall, calendar, delete,
+       // Contacts
+       email, address, phone, website,
+       // Social Media
+       facebook, twitter, linkedIn, instagram;
+
+       @Override
+       public String getClassPrefix() {
+               return "argeo-form";
+       }
+
+       // TODO clean button style management
+       public final static String BUTTON_SUFFIX = "_btn";
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormUtils.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/FormUtils.java
new file mode 100644 (file)
index 0000000..ef49c8a
--- /dev/null
@@ -0,0 +1,196 @@
+package org.argeo.cms.ui.forms;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.CmsView;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Utilitary methods to ease implementation of CMS forms */
+public class FormUtils {
+       private final static CmsLog log = CmsLog.getLog(FormUtils.class);
+
+       public final static String DEFAULT_SHORT_DATE_FORMAT = "dd/MM/yyyy";
+
+       /** Best effort to convert a String to a calendar. Fails silently */
+       public static Calendar parseDate(DateFormat dateFormat, String calStr) {
+               Calendar cal = null;
+               if (EclipseUiUtils.notEmpty(calStr)) {
+                       try {
+                               Date date = dateFormat.parse(calStr);
+                               cal = new GregorianCalendar();
+                               cal.setTime(date);
+                       } catch (ParseException pe) {
+                               // Silent
+                               log.warn("Unable to parse date: " + calStr + " - msg: "
+                                               + pe.getMessage());
+                       }
+               }
+               return cal;
+       }
+
+       /** Add a double click listener on tables that display a JCR node list */
+       public static void addCanonicalDoubleClickListener(final TableViewer v) {
+               v.addDoubleClickListener(new IDoubleClickListener() {
+
+                       @Override
+                       public void doubleClick(DoubleClickEvent event) {
+                               CmsView cmsView = CmsUiUtils.getCmsView();
+                               Node node = (Node) ((IStructuredSelection) event.getSelection())
+                                               .getFirstElement();
+                               try {
+                                       cmsView.navigateTo(node.getPath());
+                               } catch (RepositoryException e) {
+                                       throw new CmsException("Unable to get path for node "
+                                                       + node + " before calling navigateTo(path)", e);
+                               }
+                       }
+               });
+       }
+
+       // MANAGE ERROR DECORATION
+
+       public static ControlDecoration addDecoration(final Text text) {
+               final ControlDecoration dynDecoration = new ControlDecoration(text,
+                               SWT.LEFT);
+               Image icon = getDecorationImage(FieldDecorationRegistry.DEC_ERROR);
+               dynDecoration.setImage(icon);
+               dynDecoration.setMarginWidth(3);
+               dynDecoration.hide();
+               return dynDecoration;
+       }
+
+       public static void refreshDecoration(Text text, ControlDecoration deco,
+                       boolean isValid, boolean clean) {
+               if (isValid || clean) {
+                       text.setBackground(null);
+                       deco.hide();
+               } else {
+                       text.setBackground(new Color(text.getDisplay(), 250, 200, 150));
+                       deco.show();
+               }
+       }
+
+       public static Image getDecorationImage(String image) {
+               FieldDecorationRegistry registry = FieldDecorationRegistry.getDefault();
+               return registry.getFieldDecoration(image).getImage();
+       }
+
+       public static void addCompulsoryDecoration(Label label) {
+               final ControlDecoration dynDecoration = new ControlDecoration(label,
+                               SWT.RIGHT | SWT.TOP);
+               Image icon = getDecorationImage(FieldDecorationRegistry.DEC_REQUIRED);
+               dynDecoration.setImage(icon);
+               dynDecoration.setMarginWidth(3);
+       }
+
+       // TODO the read only generation of read only links for various contact type
+       // should be factorised in the cms Utils.
+       /**
+        * Creates the read-only HTML snippet to display in a label with styling
+        * enabled in order to provide a click-able phone number
+        */
+       public static String getPhoneLink(String value) {
+               return getPhoneLink(value, value);
+       }
+
+       /**
+        * Creates the read-only HTML snippet to display in a label with styling
+        * enabled in order to provide a click-able phone number
+        * 
+        * @param value
+        * @param label
+        *            a potentially distinct label
+        * @return
+        */
+       public static String getPhoneLink(String value, String label) {
+               StringBuilder builder = new StringBuilder();
+               builder.append("<a href=\"tel:");
+               builder.append(value).append("\" target=\"_blank\" >").append(label)
+                               .append("</a>");
+               return builder.toString();
+       }
+
+       /**
+        * Creates the read-only HTML snippet to display in a label with styling
+        * enabled in order to provide a click-able mail
+        */
+       public static String getMailLink(String value) {
+               return getMailLink(value, value);
+       }
+
+       /**
+        * Creates the read-only HTML snippet to display in a label with styling
+        * enabled in order to provide a click-able mail
+        * 
+        * @param value
+        * @param label
+        *            a potentially distinct label
+        * @return
+        */
+       public static String getMailLink(String value, String label) {
+               StringBuilder builder = new StringBuilder();
+               value = replaceAmpersand(value);
+               builder.append("<a href=\"mailto:");
+               builder.append(value).append("\" >").append(label).append("</a>");
+               return builder.toString();
+       }
+
+       /**
+        * Creates the read-only HTML snippet to display in a label with styling
+        * enabled in order to provide a click-able link
+        */
+       public static String getUrlLink(String value) {
+               return getUrlLink(value, value);
+       }
+
+       /**
+        * Creates the read-only HTML snippet to display in a label with styling
+        * enabled in order to provide a click-able link
+        */
+       public static String getUrlLink(String value, String label) {
+               StringBuilder builder = new StringBuilder();
+               value = replaceAmpersand(value);
+               label = replaceAmpersand(label);
+               if (!(value.startsWith("http://") || value.startsWith("https://")))
+                       value = "http://" + value;
+               builder.append("<a href=\"");
+               builder.append(value + "\" target=\"_blank\" >" + label + "</a>");
+               return builder.toString();
+       }
+
+       private static String AMPERSAND = "&#38;";
+
+       /**
+        * Cleans a String by replacing any '&#38;' by its HTML encoding '&#38;#38;' to
+        * avoid <code>SAXParseException</code> while rendering HTML with RWT
+        */
+       public static String replaceAmpersand(String value) {
+               value = value.replaceAll("&(?![#a-zA-Z0-9]+;)", AMPERSAND);
+               return value;
+       }
+
+       // Prevents instantiation
+       private FormUtils() {
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/MarkupValidatorCopy.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/MarkupValidatorCopy.java
new file mode 100644 (file)
index 0000000..3f588d1
--- /dev/null
@@ -0,0 +1,169 @@
+package org.argeo.cms.ui.forms;
+
+import java.io.StringReader;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.eclipse.rap.rwt.SingletonUtil;
+import org.eclipse.swt.widgets.Widget;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Copy of RAP v2.3 since it is in an internal package.
+ */
+class MarkupValidatorCopy {
+
+       // Used by Eclipse Scout project
+       public static final String MARKUP_VALIDATION_DISABLED = "org.eclipse.rap.rwt.markupValidationDisabled";
+
+       private static final String DTD = createDTD();
+       private static final Map<String, String[]> SUPPORTED_ELEMENTS = createSupportedElementsMap();
+       private final SAXParser saxParser;
+
+       public static MarkupValidatorCopy getInstance() {
+               return SingletonUtil.getSessionInstance(MarkupValidatorCopy.class);
+       }
+
+       public MarkupValidatorCopy() {
+               saxParser = createSAXParser();
+       }
+
+       public void validate(String text) {
+               StringBuilder markup = new StringBuilder();
+               markup.append(DTD);
+               markup.append("<html>");
+               markup.append(text);
+               markup.append("</html>");
+               InputSource inputSource = new InputSource(new StringReader(markup.toString()));
+               try {
+                       saxParser.parse(inputSource, new MarkupHandler());
+               } catch (RuntimeException exception) {
+                       throw exception;
+               } catch (Exception exception) {
+                       throw new IllegalArgumentException("Failed to parse markup text", exception);
+               }
+       }
+
+       public static boolean isValidationDisabledFor(Widget widget) {
+               return Boolean.TRUE.equals(widget.getData(MARKUP_VALIDATION_DISABLED));
+       }
+
+       private static SAXParser createSAXParser() {
+               SAXParser result = null;
+               SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+               try {
+                       result = parserFactory.newSAXParser();
+               } catch (Exception exception) {
+                       throw new RuntimeException("Failed to create SAX parser", exception);
+               }
+               return result;
+       }
+
+       private static String createDTD() {
+               StringBuilder result = new StringBuilder();
+               result.append("<!DOCTYPE html [");
+               result.append("<!ENTITY quot \"&#34;\">");
+               result.append("<!ENTITY amp \"&#38;\">");
+               result.append("<!ENTITY apos \"&#39;\">");
+               result.append("<!ENTITY lt \"&#60;\">");
+               result.append("<!ENTITY gt \"&#62;\">");
+               result.append("<!ENTITY nbsp \"&#160;\">");
+               result.append("<!ENTITY ensp \"&#8194;\">");
+               result.append("<!ENTITY emsp \"&#8195;\">");
+               result.append("<!ENTITY ndash \"&#8211;\">");
+               result.append("<!ENTITY mdash \"&#8212;\">");
+               result.append("]>");
+               return result.toString();
+       }
+
+       private static Map<String, String[]> createSupportedElementsMap() {
+               Map<String, String[]> result = new HashMap<String, String[]>();
+               result.put("html", new String[0]);
+               result.put("br", new String[0]);
+               result.put("b", new String[] { "style" });
+               result.put("strong", new String[] { "style" });
+               result.put("i", new String[] { "style" });
+               result.put("em", new String[] { "style" });
+               result.put("sub", new String[] { "style" });
+               result.put("sup", new String[] { "style" });
+               result.put("big", new String[] { "style" });
+               result.put("small", new String[] { "style" });
+               result.put("del", new String[] { "style" });
+               result.put("ins", new String[] { "style" });
+               result.put("code", new String[] { "style" });
+               result.put("samp", new String[] { "style" });
+               result.put("kbd", new String[] { "style" });
+               result.put("var", new String[] { "style" });
+               result.put("cite", new String[] { "style" });
+               result.put("dfn", new String[] { "style" });
+               result.put("q", new String[] { "style" });
+               result.put("abbr", new String[] { "style", "title" });
+               result.put("span", new String[] { "style" });
+               result.put("img", new String[] { "style", "src", "width", "height", "title", "alt" });
+               result.put("a", new String[] { "style", "href", "target", "title" });
+               return result;
+       }
+
+       private static class MarkupHandler extends DefaultHandler {
+
+               @Override
+               public void startElement(String uri, String localName, String name, Attributes attributes) {
+                       checkSupportedElements(name, attributes);
+                       checkSupportedAttributes(name, attributes);
+                       checkMandatoryAttributes(name, attributes);
+               }
+
+               private static void checkSupportedElements(String elementName, Attributes attributes) {
+                       if (!SUPPORTED_ELEMENTS.containsKey(elementName)) {
+                               throw new IllegalArgumentException("Unsupported element in markup text: " + elementName);
+                       }
+               }
+
+               private static void checkSupportedAttributes(String elementName, Attributes attributes) {
+                       if (attributes.getLength() > 0) {
+                               List<String> supportedAttributes = Arrays.asList(SUPPORTED_ELEMENTS.get(elementName));
+                               int index = 0;
+                               String attributeName = attributes.getQName(index);
+                               while (attributeName != null) {
+                                       if (!supportedAttributes.contains(attributeName)) {
+                                               String message = "Unsupported attribute \"{0}\" for element \"{1}\" in markup text";
+                                               message = MessageFormat.format(message, new Object[] { attributeName, elementName });
+                                               throw new IllegalArgumentException(message);
+                                       }
+                                       index++;
+                                       attributeName = attributes.getQName(index);
+                               }
+                       }
+               }
+
+               private static void checkMandatoryAttributes(String elementName, Attributes attributes) {
+                       checkIntAttribute(elementName, attributes, "img", "width");
+                       checkIntAttribute(elementName, attributes, "img", "height");
+               }
+
+               private static void checkIntAttribute(String elementName, Attributes attributes, String checkedElementName,
+                               String checkedAttributeName) {
+                       if (checkedElementName.equals(elementName)) {
+                               String attribute = attributes.getValue(checkedAttributeName);
+                               try {
+                                       Integer.parseInt(attribute);
+                               } catch (NumberFormatException exception) {
+                                       String message = "Mandatory attribute \"{0}\" for element \"{1}\" is missing or not a valid integer";
+                                       Object[] arguments = new Object[] { checkedAttributeName, checkedElementName };
+                                       message = MessageFormat.format(message, arguments);
+                                       throw new IllegalArgumentException(message);
+                               }
+                       }
+               }
+
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/package-info.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/forms/package-info.java
new file mode 100644 (file)
index 0000000..5f954c1
--- /dev/null
@@ -0,0 +1,2 @@
+/** Argeo CMS forms, based on SWT/JFace. */
+package org.argeo.cms.ui.forms;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/CmsFsBrowser.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/CmsFsBrowser.java
new file mode 100644 (file)
index 0000000..d9c1c12
--- /dev/null
@@ -0,0 +1,524 @@
+package org.argeo.cms.ui.fs;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.spi.FileSystemProvider;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.Session;
+
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.eclipse.ui.ColumnDefinition;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.fs.FileIconNameLabelProvider;
+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.jcr.JcrUtils;
+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 CMS browser composite: a sashForm layout with bookmarks at the left
+ * hand side, a simple table in the middle and an overview at right hand side.
+ */
+public class CmsFsBrowser extends Composite {
+       // private final static Log log = LogFactory.getLog(CmsFsBrowser.class);
+       private static final long serialVersionUID = -40347919096946585L;
+
+       private final FileSystemProvider nodeFileSystemProvider;
+       private final Node currentBaseContext;
+
+       // UI Parts for the browser
+       private Composite leftPannelCmp;
+       private Composite filterCmp;
+       private Text filterTxt;
+       private FsTableViewer directoryDisplayViewer;
+       private Composite rightPannelCmp;
+
+       private FsContextMenu contextMenu;
+
+       // Local context (this composite is state full)
+       private Path initialPath;
+       private Path currDisplayedFolder;
+       private Path currSelected;
+
+       // local variables (to be cleaned)
+       private int bookmarkColWith = 500;
+
+       /*
+        * WARNING: unfinalised implementation of the mechanism to retrieve base
+        * paths
+        */
+
+       private final static String NODE_PREFIX = "node://";
+
+       private String getCurrentHomePath() {
+               Session session = null;
+               try {
+                       Repository repo = currentBaseContext.getSession().getRepository();
+                       session = CurrentUser.tryAs(() -> repo.login());
+                       String homepath = CmsJcrUtils.getUserHome(session).getPath();
+                       return homepath;
+               } catch (Exception e) {
+                       throw new CmsException("Cannot retrieve Current User Home Path", e);
+               } finally {
+                       JcrUtils.logoutQuietly(session);
+               }
+       }
+
+       protected Path[] getMyFilesPath() {
+               // return Paths.get(System.getProperty("user.dir"));
+               String currHomeUriStr = NODE_PREFIX + getCurrentHomePath();
+               try {
+                       URI uri = new URI(currHomeUriStr);
+                       FileSystem fileSystem = nodeFileSystemProvider.getFileSystem(uri);
+                       if (fileSystem == null) {
+                               PrivilegedExceptionAction<FileSystem> pea = new PrivilegedExceptionAction<FileSystem>() {
+                                       @Override
+                                       public FileSystem run() throws Exception {
+                                               return nodeFileSystemProvider.newFileSystem(uri, null);
+                                       }
+
+                               };
+                               fileSystem = CurrentUser.tryAs(pea);
+                       }
+                       Path[] paths = { fileSystem.getPath(getCurrentHomePath()), fileSystem.getPath("/") };
+                       return paths;
+               } catch (URISyntaxException | PrivilegedActionException e) {
+                       throw new RuntimeException("unable to initialise home file system for " + currHomeUriStr, e);
+               }
+       }
+
+       private Path[] getMyGroupsFilesPath() {
+               // TODO
+               Path[] paths = { Paths.get(System.getProperty("user.dir")), Paths.get("/tmp") };
+               return paths;
+       }
+
+       private Path[] getMyBookmarks() {
+               // TODO
+               Path[] paths = { Paths.get(System.getProperty("user.dir")), Paths.get("/tmp"), Paths.get("/opt") };
+               return paths;
+       }
+
+       /* End of warning */
+
+       public CmsFsBrowser(Composite parent, int style, Node context, FileSystemProvider fileSystemProvider) {
+               super(parent, style);
+               this.nodeFileSystemProvider = fileSystemProvider;
+               this.currentBaseContext = context;
+
+               this.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+               SashForm form = new SashForm(this, SWT.HORIZONTAL);
+
+               leftPannelCmp = new Composite(form, SWT.NO_FOCUS);
+               // Bookmarks are still static
+               populateBookmarks(leftPannelCmp);
+
+               Composite centerCmp = new Composite(form, SWT.BORDER | SWT.NO_FOCUS);
+               createDisplay(centerCmp);
+
+               rightPannelCmp = new Composite(form, SWT.NO_FOCUS);
+
+               form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               form.setWeights(new int[] { 15, 40, 20 });
+       }
+
+       void refresh() {
+               modifyFilter(false);
+               // also refresh bookmarks and groups
+       }
+
+       private void createDisplay(final Composite parent) {
+               parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+               // top filter
+               filterCmp = new Composite(parent, SWT.NO_FOCUS);
+               filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
+               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());
+
+               // table.addKeyListener(new KeyListener() {
+               // private static final long serialVersionUID = -8083424284436715709L;
+               //
+               // @Override
+               // public void keyReleased(KeyEvent e) {
+               // }
+               //
+               // @Override
+               // public void keyPressed(KeyEvent e) {
+               // if (log.isDebugEnabled())
+               // log.debug("Key event received: " + e.keyCode);
+               // IStructuredSelection selection = (IStructuredSelection)
+               // directoryDisplayViewer.getSelection();
+               // Path selected = null;
+               // if (!selection.isEmpty())
+               // selected = ((Path) selection.getFirstElement());
+               // if (e.keyCode == SWT.CR) {
+               // if (!Files.isDirectory(selected))
+               // return;
+               // if (selected != null) {
+               // currDisplayedFolder = selected;
+               // directoryDisplayViewer.setInput(currDisplayedFolder, "*");
+               // }
+               // } else if (e.keyCode == SWT.BS) {
+               // currDisplayedFolder = currDisplayedFolder.getParent();
+               // directoryDisplayViewer.setInput(currDisplayedFolder, "*");
+               // directoryDisplayViewer.getTable().setFocus();
+               // }
+               // }
+               // });
+
+               directoryDisplayViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+                       @Override
+                       public void selectionChanged(SelectionChangedEvent event) {
+                               IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
+                               Path selected = null;
+                               if (selection.isEmpty())
+                                       setSelected(null);
+                               else
+                                       selected = ((Path) selection.getFirstElement());
+                               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())
+                                       selected = ((Path) selection.getFirstElement());
+                               if (selected != null) {
+                                       if (!Files.isDirectory(selected))
+                                               return;
+                                       setInput(selected);
+                               }
+                       }
+               });
+
+               // The context menu
+               contextMenu = new FsContextMenu(this);
+
+               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), currDisplayedFolder);
+                               }
+                       }
+               });
+       }
+
+       private void addPathElementBtn(Path path) {
+               Button elemBtn = new Button(filterCmp, SWT.PUSH);
+               String nameStr;
+               if (path.toString().equals("/"))
+                       nameStr = "[jcr:root]";
+               else
+                       nameStr = path.getFileName().toString();
+               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(currDisplayedFolder))
+                       return;
+               currDisplayedFolder = path;
+
+               Path diff = initialPath.relativize(currDisplayedFolder);
+
+               for (Control child : filterCmp.getChildren())
+                       if (!child.equals(filterTxt))
+                               child.dispose();
+
+               addPathElementBtn(initialPath);
+               Path currTarget = initialPath;
+               if (!diff.toString().equals(""))
+                       for (Path pathElem : diff) {
+                               currTarget = currTarget.resolve(pathElem);
+                               addPathElementBtn(currTarget);
+                       }
+
+               filterTxt.setText("");
+               filterTxt.moveBelow(null);
+               setSelected(null);
+               filterCmp.getParent().layout(true, true);
+       }
+
+       private void setSelected(Path path) {
+               currSelected = path;
+               setOverviewInput(path);
+       }
+
+       public Viewer getViewer() {
+               return directoryDisplayViewer;
+       }
+
+       private void populateBookmarks(Composite parent) {
+               CmsSwtUtils.clear(parent);
+               parent.setLayout(new GridLayout());
+               ISelectionChangedListener selList = new BookmarksSelChangeListener();
+
+               FsTableViewer homeViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
+               Table table = homeViewer.configureDefaultSingleColumnTable(bookmarkColWith);
+               GridData gd = EclipseUiUtils.fillWidth();
+               gd.horizontalIndent = 10;
+               table.setLayoutData(gd);
+               homeViewer.addSelectionChangedListener(selList);
+               homeViewer.setPathsInput(getMyFilesPath());
+
+               appendTitle(parent, "Shared files");
+               FsTableViewer groupsViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
+               table = groupsViewer.configureDefaultSingleColumnTable(bookmarkColWith);
+               gd = EclipseUiUtils.fillWidth();
+               gd.horizontalIndent = 10;
+               table.setLayoutData(gd);
+               groupsViewer.addSelectionChangedListener(selList);
+               groupsViewer.setPathsInput(getMyGroupsFilesPath());
+
+               appendTitle(parent, "My bookmarks");
+               FsTableViewer bookmarksViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
+               table = bookmarksViewer.configureDefaultSingleColumnTable(bookmarkColWith);
+               gd = EclipseUiUtils.fillWidth();
+               gd.horizontalIndent = 10;
+               table.setLayoutData(gd);
+               bookmarksViewer.addSelectionChangedListener(selList);
+               bookmarksViewer.setPathsInput(getMyBookmarks());
+       }
+
+       /**
+        * 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 CmsException("Cannot display details for " + path.toString(), e);
+               }
+       }
+
+       private void addFilterPanel(Composite parent) {
+               RowLayout rl = new RowLayout(SWT.HORIZONTAL);
+               rl.wrap = true;
+               parent.setLayout(rl);
+               // 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 CmsException(
+                                       "Unable to determine unique child existence and get it under " + parent + " with filter " + filter,
+                                       ioe);
+               }
+       }
+
+       private void modifyFilter(boolean fromOutside) {
+               if (!fromOutside)
+                       if (currDisplayedFolder != null) {
+                               String filter = filterTxt.getText() + "*";
+                               directoryDisplayViewer.setInput(currDisplayedFolder, filter);
+                       }
+       }
+
+       private class BookmarksSelChangeListener implements ISelectionChangedListener {
+
+               @Override
+               public void selectionChanged(SelectionChangedEvent event) {
+                       IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+                       if (selection.isEmpty())
+                               return;
+                       else {
+                               Path newSelected = (Path) selection.getFirstElement();
+                               if (newSelected.equals(currDisplayedFolder) && newSelected.equals(initialPath))
+                                       return;
+                               initialPath = newSelected;
+                               setInput(newSelected);
+                       }
+               }
+       }
+
+       // Simplify UI implementation
+       private void addProperty(Composite parent, String propName, String value) {
+               Label contextL = new Label(parent, SWT.NONE);
+               contextL.setText(propName + ": " + value);
+       }
+
+       private Label appendTitle(Composite parent, String value) {
+               Label titleLbl = new Label(parent, SWT.NONE);
+               titleLbl.setText(value);
+               titleLbl.setFont(EclipseUiUtils.getBoldFont(parent));
+               GridData gd = EclipseUiUtils.fillWidth();
+               gd.horizontalIndent = 5;
+               gd.verticalIndent = 5;
+               titleLbl.setLayoutData(gd);
+               return titleLbl;
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/FileDrop.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/FileDrop.java
new file mode 100644 (file)
index 0000000..e875b5a
--- /dev/null
@@ -0,0 +1,37 @@
+package org.argeo.cms.ui.fs;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.eclipse.ui.specific.FileDropAdapter;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DropTarget;
+import org.eclipse.swt.dnd.DropTargetEvent;
+import org.eclipse.swt.widgets.Control;
+
+/** Allows a control to receive file drops. */
+public class FileDrop {
+       private final static CmsLog log = CmsLog.getLog(FileDrop.class);
+
+       public void createDropTarget(Control control) {
+               FileDropAdapter fileDropAdapter = new FileDropAdapter() {
+                       @Override
+                       protected void processUpload(InputStream in, String fileName, String contentType) throws IOException {
+                               if (log.isDebugEnabled())
+                                       log.debug("Process upload of " + fileName + " (" + contentType + ")");
+                               processFileUpload(in, fileName, contentType);
+                       }
+               };
+               DropTarget dropTarget = new DropTarget(control, DND.DROP_MOVE | DND.DROP_COPY);
+               fileDropAdapter.prepareDropTarget(control, dropTarget);
+       }
+
+       public void handleFileDrop(Control control, DropTargetEvent event) {
+       }
+
+       /** Executed in UI thread */
+       protected void processFileUpload(InputStream in, String fileName, String contentType) throws IOException {
+
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/FsContextMenu.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/FsContextMenu.java
new file mode 100644 (file)
index 0000000..1fb3c2a
--- /dev/null
@@ -0,0 +1,383 @@
+package org.argeo.cms.ui.fs;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.eclipse.ui.dialogs.SingleValue;
+import org.eclipse.jface.dialogs.MessageDialog;
+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.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/** Generic popup context menu to manage NIO Path in a Viewer. */
+public class FsContextMenu extends Shell {
+       private static final long serialVersionUID = -9120261153509855795L;
+
+       private final static CmsLog log = CmsLog.getLog(FsContextMenu.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_DELETE = "delete";
+       public final static String ACTION_ID_UPLOAD_FILE = "uploadFiles";
+       public final static String ACTION_ID_OPEN = "open";
+
+       // Local context
+       private final CmsFsBrowser browser;
+       // private final Viewer viewer;
+       private final static String KEY_ACTION_ID = "actionId";
+       private final static String[] DEFAULT_ACTIONS = { ACTION_ID_CREATE_FOLDER, ACTION_ID_BOOKMARK_FOLDER,
+                       ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_DELETE, ACTION_ID_UPLOAD_FILE,
+                       ACTION_ID_OPEN };
+       private Map<String, Button> actionButtons = new HashMap<String, Button>();
+
+       private Path currFolderPath;
+
+       public FsContextMenu(CmsFsBrowser browser) { // Viewer viewer, Display
+                                                                                                       // display) {
+               super(browser.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+               this.browser = browser;
+               setLayout(EclipseUiUtils.noSpaceGridLayout());
+
+               Composite boxCmp = new Composite(this, SWT.NO_FOCUS | SWT.BORDER);
+               boxCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
+               CmsSwtUtils.style(boxCmp, FsStyles.CONTEXT_MENU_BOX);
+               createContextMenu(boxCmp);
+
+               addShellListener(new ActionsShellListener());
+       }
+
+       protected void createContextMenu(Composite boxCmp) {
+               ActionsSelListener asl = new ActionsSelListener();
+               for (String actionId : DEFAULT_ACTIONS) {
+                       Button btn = new Button(boxCmp, SWT.FLAT | SWT.PUSH | SWT.LEAD);
+                       btn.setText(getLabel(actionId));
+                       btn.setLayoutData(EclipseUiUtils.fillWidth());
+                       CmsSwtUtils.markup(btn);
+                       CmsSwtUtils.style(btn, actionId + FsStyles.BUTTON_SUFFIX);
+                       btn.setData(KEY_ACTION_ID, actionId);
+                       btn.addSelectionListener(asl);
+                       actionButtons.put(actionId, btn);
+               }
+       }
+
+       protected 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_DELETE:
+                       return "Delete";
+               case ACTION_ID_UPLOAD_FILE:
+                       return "Upload Files";
+               case ACTION_ID_OPEN:
+                       return "Open";
+               default:
+                       throw new IllegalArgumentException("Unknown action ID " + actionId);
+               }
+       }
+
+       protected void aboutToShow(Control source, Point location) {
+               IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
+               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);
+                       setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_DELETE, ACTION_ID_OPEN,
+                                       // to be implemented
+                                       ACTION_ID_BOOKMARK_FOLDER);
+               } else if (multiSel) {
+                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_DELETE);
+                       setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_OPEN,
+                                       // to be implemented
+                                       ACTION_ID_BOOKMARK_FOLDER);
+               } else if (isFolder) {
+                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_DELETE);
+                       setVisible(false, ACTION_ID_OPEN,
+                                       // to be implemented
+                                       ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_BOOKMARK_FOLDER);
+               } else {
+                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_OPEN, ACTION_ID_DELETE);
+                       setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER,
+                                       // to be implemented
+                                       ACTION_ID_BOOKMARK_FOLDER);
+               }
+       }
+
+       private 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, Path currFolderPath) {
+               if (isVisible())
+                       setVisible(false);
+               // 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;
+               aboutToShow(source, location);
+               pack();
+               layout();
+               if (source instanceof Control)
+                       setLocation(((Control) source).toDisplay(location.x, location.y));
+               open();
+       }
+
+       class StyleButton extends Label {
+               private static final long serialVersionUID = 7731102609123946115L;
+
+               public StyleButton(Composite parent, int swtStyle) {
+                       super(parent, swtStyle);
+               }
+
+       }
+
+       // class ActionsMouseListener extends MouseAdapter {
+       // private static final long serialVersionUID = -1041871937815812149L;
+       //
+       // @Override
+       // public void mouseDown(MouseEvent e) {
+       // Object eventSource = e.getSource();
+       // if (e.button == 1) {
+       // if (eventSource instanceof Button) {
+       // Button pressedBtn = (Button) eventSource;
+       // String actionId = (String) pressedBtn.getData(KEY_ACTION_ID);
+       // switch (actionId) {
+       // case ACTION_ID_CREATE_FOLDER:
+       // createFolder();
+       // break;
+       // case ACTION_ID_DELETE:
+       // deleteItems();
+       // 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";
+       // // case ACTION_ID_UPLOAD_FILE:
+       // // return "Upload Files";
+       // // case ACTION_ID_OPEN:
+       // // return "Open";
+       // }
+       // }
+       // }
+       // viewer.getControl().setFocus();
+       // // setVisible(false);
+       // }
+       // }
+
+       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;
+                               String actionId = (String) pressedBtn.getData(KEY_ACTION_ID);
+                               switch (actionId) {
+                               case ACTION_ID_CREATE_FOLDER:
+                                       createFolder();
+                                       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";
+                                       // case ACTION_ID_OPEN:
+                                       // return "Open";
+                               }
+                       }
+                       browser.setFocus();
+                       // viewer.getControl().setFocus();
+                       // setVisible(false);
+
+               }
+       }
+
+       class ActionsShellListener extends org.eclipse.swt.events.ShellAdapter {
+               private static final long serialVersionUID = -5092341449523150827L;
+
+               @Override
+               public void shellDeactivated(ShellEvent e) {
+                       setVisible(false);
+               }
+       }
+
+       private void openFile() {
+               log.warn("Implement single sourced, workbench independant \"Open File\" action");
+       }
+
+       private void deleteItems() {
+               IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
+               if (selection.isEmpty())
+                       return;
+
+               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 (MessageDialog.openConfirm(this, "Confirm deletion", msg)) {
+                       for (Path path : paths) {
+                               try {
+                                       // Might have already been deleted if we are in a tree
+                                       Files.deleteIfExists(path);
+                               } catch (IOException e) {
+                                       throw new CmsException("Cannot delete path " + path, e);
+                               }
+                       }
+                       browser.refresh();
+               }
+       }
+
+       private void createFolder() {
+               String msg = "Please provide a name.";
+               String name = SingleValue.ask("Create folder", msg);
+               // TODO enhance check of name validity
+               if (EclipseUiUtils.notEmpty(name)) {
+                       try {
+                               Path child = currFolderPath.resolve(name);
+                               if (Files.exists(child))
+                                       throw new CmsException("An item with name " + name + " already exists at "
+                                                       + currFolderPath.toString() + ", cannot create");
+                               else
+                                       Files.createDirectories(child);
+                               browser.refresh();
+                       } catch (IOException e) {
+                               throw new CmsException("Cannot create folder " + name + " at " + currFolderPath.toString(), e);
+                       }
+               }
+       }
+
+       private void uploadFiles() {
+               try {
+                       FileDialog dialog = new FileDialog(browser.getShell(), 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;
+                               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)) {
+                                                               MessageDialog.openError(browser.getShell(), "Unimplemented directory import",
+                                                                               "Upload of directories in the system is not yet implemented");
+                                                               continue loop;
+                                                       }
+                                                       Path targetPath = currFolderPath.resolve(tmpPath.getFileName().toString());
+                                                       InputStream in = null;
+                                                       try {
+                                                               in = new ByteArrayInputStream(Files.readAllBytes(tmpPath));
+                                                               Files.copy(in, targetPath);
+                                                               Files.delete(tmpPath);
+                                                       } finally {
+                                                               IOUtils.closeQuietly(in);
+                                                       }
+                                                       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";
+                                                       MessageDialog.openError(browser.getShell(), "Missing file", msg);
+                                                       continue loop;
+                                               }
+                                       }
+                                       browser.refresh();
+                               }
+                       }
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       MessageDialog.openError(getShell(), "Upload has failed", "Cannot import files to " + currFolderPath);
+               }
+       }
+
+       public void setCurrFolderPath(Path currFolderPath) {
+               this.currFolderPath = currFolderPath;
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/FsStyles.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/FsStyles.java
new file mode 100644 (file)
index 0000000..9ae3192
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.cms.ui.fs;
+
+/** FS Ui specific CSS styles */
+public interface FsStyles {
+       String BREAD_CRUMB_BTN = "breadCrumb_btn";
+       String CONTEXT_MENU_BOX = "contextMenu_box";
+       String BUTTON_SUFFIX = "_btn";
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/package-info.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/fs/package-info.java
new file mode 100644 (file)
index 0000000..6a6c272
--- /dev/null
@@ -0,0 +1,2 @@
+/** SWT/JFace file system components. */
+package org.argeo.cms.ui.fs;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/internal/Activator.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/internal/Activator.java
new file mode 100644 (file)
index 0000000..e10da3a
--- /dev/null
@@ -0,0 +1,37 @@
+package org.argeo.cms.ui.internal;
+
+import org.argeo.api.cms.CmsState;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class Activator implements BundleActivator {
+
+       // avoid dependency to RWT OSGi
+       private final static String CONTEXT_NAME_PROP = "contextName";
+
+       private static ServiceTracker<CmsState, CmsState> nodeState;
+
+       // @Override
+       public void start(BundleContext bc) throws Exception {
+               // UI
+//             bc.registerService(ApplicationConfiguration.class, new MaintenanceUi(),
+//                             LangUtils.dico(CONTEXT_NAME_PROP, "system"));
+//             bc.registerService(ApplicationConfiguration.class, new UserUi(), LangUtils.dico(CONTEXT_NAME_PROP, "user"));
+
+               nodeState = new ServiceTracker<>(bc, CmsState.class, null);
+               nodeState.open();
+       }
+
+       @Override
+       public void stop(BundleContext context) throws Exception {
+               if (nodeState != null) {
+                       nodeState.close();
+                       nodeState = null;
+               }
+       }
+
+       public static CmsState getNodeState() {
+               return nodeState.getService();
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/internal/JcrContentProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/internal/JcrContentProvider.java
new file mode 100644 (file)
index 0000000..ea0abdf
--- /dev/null
@@ -0,0 +1,81 @@
+package org.argeo.cms.ui.internal;
+
+import java.util.ArrayList;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.CmsException;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+@Deprecated
+class JcrContentProvider implements ITreeContentProvider {
+       private static final long serialVersionUID = -1333678161322488674L;
+
+       @Override
+       public void dispose() {
+       }
+
+       @Override
+       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+               if (newInput == null)
+                       return;
+               if (!(newInput instanceof Node))
+                       throw new CmsException("Input " + newInput + " must be a node");
+       }
+
+       @Override
+       public Object[] getElements(Object inputElement) {
+               try {
+                       Node node = (Node) inputElement;
+                       ArrayList<Node> arr = new ArrayList<Node>();
+                       NodeIterator nit = node.getNodes();
+                       while (nit.hasNext()) {
+                               arr.add(nit.nextNode());
+                       }
+                       return arr.toArray();
+               } catch (RepositoryException e) {
+                       throw new CmsException("Cannot get elements", e);
+               }
+       }
+
+       @Override
+       public Object[] getChildren(Object parentElement) {
+               try {
+                       Node node = (Node) parentElement;
+                       ArrayList<Node> arr = new ArrayList<Node>();
+                       NodeIterator nit = node.getNodes();
+                       while (nit.hasNext()) {
+                               arr.add(nit.nextNode());
+                       }
+                       return arr.toArray();
+               } catch (RepositoryException e) {
+                       throw new CmsException("Cannot get elements", e);
+               }
+       }
+
+       @Override
+       public Object getParent(Object element) {
+               try {
+                       Node node = (Node) element;
+                       if (node.getName().equals(""))
+                               return null;
+                       else
+                               return node.getParent();
+               } catch (RepositoryException e) {
+                       throw new CmsException("Cannot get elements", e);
+               }
+       }
+
+       @Override
+       public boolean hasChildren(Object element) {
+               try {
+                       Node node = (Node) element;
+                       return node.hasNodes();
+               } catch (RepositoryException e) {
+                       throw new CmsException("Cannot get elements", e);
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/internal/JcrFileUploadReceiver.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/internal/JcrFileUploadReceiver.java
new file mode 100644 (file)
index 0000000..60bb42b
--- /dev/null
@@ -0,0 +1,74 @@
+package org.argeo.cms.ui.internal;
+
+import static javax.jcr.nodetype.NodeType.NT_FILE;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.commons.io.FilenameUtils;
+import org.argeo.api.cms.ux.CmsImageManager;
+import org.argeo.cms.ui.widgets.Img;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.rap.fileupload.FileDetails;
+import org.eclipse.rap.fileupload.FileUploadReceiver;
+
+public class JcrFileUploadReceiver extends FileUploadReceiver {
+       private Img img;
+       private final Node parentNode;
+       private final String nodeName;
+       private final CmsImageManager imageManager;
+
+       /** If nodeName is null, use the uploaded file name */
+       public JcrFileUploadReceiver(Img img, Node parentNode, String nodeName, CmsImageManager imageManager) {
+               super();
+               this.img = img;
+               this.parentNode = parentNode;
+               this.nodeName = nodeName;
+               this.imageManager = imageManager;
+       }
+
+       @Override
+       public void receive(InputStream stream, FileDetails details) throws IOException {
+               try {
+                       String fileName = nodeName != null ? nodeName : details.getFileName();
+                       String contentType = details.getContentType();
+                       if (isImage(details.getFileName(), contentType)) {
+                               imageManager.uploadImage(img.getNode(),parentNode, fileName, stream, contentType);
+                               return;
+                       }
+
+                       Node fileNode;
+                       if (parentNode.hasNode(fileName)) {
+                               fileNode = parentNode.getNode(fileName);
+                               if (!fileNode.isNodeType(NT_FILE))
+                                       fileNode.remove();
+                       }
+                       fileNode = JcrUtils.copyStreamAsFile(parentNode, fileName, stream);
+
+                       if (contentType != null) {
+                               fileNode.addMixin(NodeType.MIX_MIMETYPE);
+                               fileNode.setProperty(Property.JCR_MIMETYPE, contentType);
+                       }
+                       processNewFile(fileNode);
+                       fileNode.getSession().save();
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot receive " + details, e);
+               }
+       }
+
+       protected Boolean isImage(String fileName, String contentType) {
+               String ext = FilenameUtils.getExtension(fileName);
+               return ext != null && (ext.equals("png") || ext.equalsIgnoreCase("jpg"));
+       }
+
+       protected void processNewFile(Node node) {
+
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/internal/SimpleEditableImage.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/internal/SimpleEditableImage.java
new file mode 100644 (file)
index 0000000..6162a74
--- /dev/null
@@ -0,0 +1,74 @@
+package org.argeo.cms.ui.internal;
+
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.widgets.EditableImage;
+import org.argeo.cms.ux.AbstractImageManager;
+import org.argeo.cms.ux.CmsUxUtils;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+
+/** NOT working yet. */
+public class SimpleEditableImage extends EditableImage {
+       private static final long serialVersionUID = -5689145523114022890L;
+
+       private String src;
+       private Cms2DSize imageSize;
+
+       public SimpleEditableImage(Composite parent, int swtStyle) {
+               super(parent, swtStyle);
+               // load(getControl());
+               getParent().layout();
+       }
+
+       public SimpleEditableImage(Composite parent, int swtStyle, String src, Cms2DSize imageSize) {
+               super(parent, swtStyle);
+               this.src = src;
+               this.imageSize = imageSize;
+       }
+
+       @Override
+       protected Control createControl(Composite box, String style) {
+               if (isEditing()) {
+                       return createText(box, style);
+               } else {
+                       return createLabel(box, style);
+               }
+       }
+
+       protected String createImgTag() throws RepositoryException {
+               String imgTag;
+               if (src != null)
+                       imgTag = CmsUxUtils.img(src, imageSize);
+               else
+                       imgTag = CmsUiUtils.noImg(imageSize != null ? imageSize : AbstractImageManager.NO_IMAGE_SIZE);
+               return imgTag;
+       }
+
+       protected Text createText(Composite box, String style) {
+               Text text = new Text(box, getStyle());
+               CmsSwtUtils.style(text, style);
+               return text;
+       }
+
+       public String getSrc() {
+               return src;
+       }
+
+       public void setSrc(String src) {
+               this.src = src;
+       }
+
+       public Cms2DSize getImageSize() {
+               return imageSize;
+       }
+
+       public void setImageSize(Cms2DSize imageSize) {
+               this.imageSize = imageSize;
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/DefaultRepositoryRegister.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/DefaultRepositoryRegister.java
new file mode 100644 (file)
index 0000000..3806341
--- /dev/null
@@ -0,0 +1,75 @@
+package org.argeo.cms.ui.jcr;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Observable;
+import java.util.TreeMap;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
+
+public class DefaultRepositoryRegister extends Observable implements RepositoryRegister {
+       /** Key for a JCR repository alias */
+       private final static String CN = CmsConstants.CN;
+       /** Key for a JCR repository URI */
+       // public final static String JCR_REPOSITORY_URI = "argeo.jcr.repository.uri";
+       private final static CmsLog log = CmsLog.getLog(DefaultRepositoryRegister.class);
+
+       /** Read only map which will be directly exposed. */
+       private Map<String, Repository> repositories = Collections.unmodifiableMap(new TreeMap<String, Repository>());
+
+       @SuppressWarnings("rawtypes")
+       public synchronized Repository getRepository(Map parameters) throws RepositoryException {
+               if (!parameters.containsKey(CN))
+                       throw new RepositoryException("Parameter " + CN + " has to be defined.");
+               String alias = parameters.get(CN).toString();
+               if (!repositories.containsKey(alias))
+                       throw new RepositoryException("No repository registered with alias " + alias);
+
+               return repositories.get(alias);
+       }
+
+       /** Access to the read-only map */
+       public synchronized Map<String, Repository> getRepositories() {
+               return repositories;
+       }
+
+       /** Registers a service, typically called when OSGi services are bound. */
+       @SuppressWarnings("rawtypes")
+       public synchronized void register(Repository repository, Map properties) {
+               String alias;
+               if (properties == null || !properties.containsKey(CN)) {
+                       log.warn("Cannot register a repository if no " + CN + " property is specified.");
+                       return;
+               }
+               alias = properties.get(CN).toString();
+               Map<String, Repository> map = new TreeMap<String, Repository>(repositories);
+               map.put(alias, repository);
+               repositories = Collections.unmodifiableMap(map);
+               setChanged();
+               notifyObservers(alias);
+       }
+
+       /** Unregisters a service, typically called when OSGi services are unbound. */
+       @SuppressWarnings("rawtypes")
+       public synchronized void unregister(Repository repository, Map properties) {
+               // TODO: also check bean name?
+               if (properties == null || !properties.containsKey(CN)) {
+                       log.warn("Cannot unregister a repository without property " + CN);
+                       return;
+               }
+
+               String alias = properties.get(CN).toString();
+               Map<String, Repository> map = new TreeMap<String, Repository>(repositories);
+               if (map.remove(alias) == null) {
+                       log.warn("No repository was registered with alias " + alias);
+                       return;
+               }
+               repositories = Collections.unmodifiableMap(map);
+               setChanged();
+               notifyObservers(alias);
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/FullVersioningTreeContentProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/FullVersioningTreeContentProvider.java
new file mode 100644 (file)
index 0000000..0f7ee77
--- /dev/null
@@ -0,0 +1,98 @@
+package org.argeo.cms.ui.jcr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.VersionIterator;
+import javax.jcr.version.VersionManager;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * Display some version information of a JCR full versionable node in a tree
+ * like structure
+ */
+public class FullVersioningTreeContentProvider implements ITreeContentProvider {
+       private static final long serialVersionUID = 8691772509491211112L;
+
+       /**
+        * Sends back the first level of the Tree. input element must be a single
+        * node object
+        */
+       public Object[] getElements(Object inputElement) {
+               try {
+                       Node rootNode = (Node) inputElement;
+                       String curPath = rootNode.getPath();
+                       VersionManager vm = rootNode.getSession().getWorkspace()
+                                       .getVersionManager();
+
+                       VersionHistory vh = vm.getVersionHistory(curPath);
+                       List<Version> result = new ArrayList<Version>();
+                       VersionIterator vi = vh.getAllLinearVersions();
+
+                       while (vi.hasNext()) {
+                               result.add(vi.nextVersion());
+                       }
+                       return result.toArray();
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException(
+                                       "Unexpected error while getting version elements", re);
+               }
+       }
+
+       public Object[] getChildren(Object parentElement) {
+               try {
+                       if (parentElement instanceof Version) {
+                               List<Node> tmp = new ArrayList<Node>();
+                               tmp.add(((Version) parentElement).getFrozenNode());
+                               return tmp.toArray();
+                       }
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Unexpected error while getting child "
+                                       + "node for version element", re);
+               }
+               return null;
+       }
+
+       public Object getParent(Object element) {
+               try {
+                       // this will not work in a simpleVersionning environment, parent is
+                       // not a node.
+                       if (element instanceof Node
+                                       && ((Node) element).isNodeType(NodeType.NT_FROZEN_NODE)) {
+                               Node node = (Node) element;
+                               return node.getParent();
+                       } else
+                               return null;
+               } catch (RepositoryException e) {
+                       return null;
+               }
+       }
+
+       public boolean hasChildren(Object element) {
+               try {
+                       if (element instanceof Version)
+                               return true;
+                       else if (element instanceof Node)
+                               return ((Node) element).hasNodes();
+                       else
+                               return false;
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot check children of " + element, e);
+               }
+       }
+
+       public void dispose() {
+       }
+
+       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/JcrBrowserUtils.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/JcrBrowserUtils.java
new file mode 100644 (file)
index 0000000..b36acc3
--- /dev/null
@@ -0,0 +1,68 @@
+package org.argeo.cms.ui.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.ui.jcr.model.RepositoriesElem;
+import org.argeo.cms.ui.jcr.model.RepositoryElem;
+import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
+import org.argeo.cms.ui.jcr.model.WorkspaceElem;
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.argeo.eclipse.ui.EclipseUiException;
+
+/** Useful methods to manage the JCR Browser */
+public class JcrBrowserUtils {
+
+       public static String getPropertyTypeAsString(Property prop) {
+               try {
+                       return PropertyType.nameFromValue(prop.getType());
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot check type for " + prop, e);
+               }
+       }
+
+       /** Insure that the UI component is not stale, refresh if needed */
+       public static void forceRefreshIfNeeded(TreeParent element) {
+               Node curNode = null;
+
+               boolean doRefresh = false;
+
+               try {
+                       if (element instanceof SingleJcrNodeElem) {
+                               curNode = ((SingleJcrNodeElem) element).getNode();
+                       } else if (element instanceof WorkspaceElem) {
+                               curNode = ((WorkspaceElem) element).getRootNode();
+                       }
+
+                       if (curNode != null && element.getChildren().length != curNode.getNodes().getSize())
+                               doRefresh = true;
+                       else if (element instanceof RepositoryElem) {
+                               RepositoryElem rn = (RepositoryElem) element;
+                               if (rn.isConnected()) {
+                                       String[] wkpNames = rn.getAccessibleWorkspaceNames();
+                                       if (element.getChildren().length != wkpNames.length)
+                                               doRefresh = true;
+                               }
+                       } else if (element instanceof RepositoriesElem) {
+                               doRefresh = true;
+                               // Always force refresh for RepositoriesElem : the condition
+                               // below does not take remote repository into account and it is
+                               // not trivial to do so.
+
+                               // RepositoriesElem rn = (RepositoriesElem) element;
+                               // if (element.getChildren().length !=
+                               // rn.getRepositoryRegister()
+                               // .getRepositories().size())
+                               // doRefresh = true;
+                       }
+                       if (doRefresh) {
+                               element.clearChildren();
+                               element.getChildren();
+                       }
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Unexpected error while synchronising the UI with the JCR repository", re);
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/JcrDClickListener.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/JcrDClickListener.java
new file mode 100644 (file)
index 0000000..1707681
--- /dev/null
@@ -0,0 +1,60 @@
+package org.argeo.cms.ui.jcr;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.ui.jcr.model.RepositoryElem;
+import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
+import org.argeo.cms.ui.jcr.model.WorkspaceElem;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+
+/** Centralizes the management of double click on a NodeTreeViewer */
+public class JcrDClickListener implements IDoubleClickListener {
+       // private final static Log log = LogFactory
+       // .getLog(GenericNodeDoubleClickListener.class);
+
+       private TreeViewer nodeViewer;
+
+       // private JcrFileProvider jfp;
+       // private FileHandler fileHandler;
+
+       public JcrDClickListener(TreeViewer nodeViewer) {
+               this.nodeViewer = nodeViewer;
+               // jfp = new JcrFileProvider();
+               // Commented out. see https://www.argeo.org/bugzilla/show_bug.cgi?id=188
+               // fileHandler = null;
+               // fileHandler = new FileHandler(jfp);
+       }
+
+       public void doubleClick(DoubleClickEvent event) {
+               if (event.getSelection() == null || event.getSelection().isEmpty())
+                       return;
+               Object obj = ((IStructuredSelection) event.getSelection()).getFirstElement();
+               if (obj instanceof RepositoryElem) {
+                       RepositoryElem rpNode = (RepositoryElem) obj;
+                       if (rpNode.isConnected()) {
+                               rpNode.logout();
+                       } else {
+                               rpNode.login();
+                       }
+                       nodeViewer.refresh(obj);
+               } else if (obj instanceof WorkspaceElem) {
+                       WorkspaceElem wn = (WorkspaceElem) obj;
+                       if (wn.isConnected())
+                               wn.logout();
+                       else
+                               wn.login();
+                       nodeViewer.refresh(obj);
+               } else if (obj instanceof SingleJcrNodeElem) {
+                       SingleJcrNodeElem sjn = (SingleJcrNodeElem) obj;
+                       Node node = sjn.getNode();
+                       openNode(node);
+               }
+       }
+
+       protected void openNode(Node node) {
+               // TODO implement generic behaviour
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/JcrImages.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/JcrImages.java
new file mode 100644 (file)
index 0000000..d1d1e31
--- /dev/null
@@ -0,0 +1,24 @@
+package org.argeo.cms.ui.jcr;
+
+import org.argeo.cms.ui.theme.CmsImages;
+import org.eclipse.swt.graphics.Image;
+
+/** Shared icons. */
+public class JcrImages {
+       public final static Image NODE = CmsImages.createIcon("node.gif");
+       public final static Image FOLDER = CmsImages.createIcon("folder.gif");
+       public final static Image FILE = CmsImages.createIcon("file.gif");
+       public final static Image BINARY = CmsImages.createIcon("binary.png");
+       public final static Image HOME = CmsImages.createIcon("person-logged-in.png");
+       public final static Image SORT = CmsImages.createIcon("sort.gif");
+       public final static Image REMOVE = CmsImages.createIcon("remove.gif");
+
+       public final static Image REPOSITORIES = CmsImages.createIcon("repositories.gif");
+       public final static Image REPOSITORY_DISCONNECTED = CmsImages.createIcon("repository_disconnected.gif");
+       public final static Image REPOSITORY_CONNECTED = CmsImages.createIcon("repository_connected.gif");
+       public final static Image REMOTE_DISCONNECTED = CmsImages.createIcon("remote_disconnected.gif");
+       public final static Image REMOTE_CONNECTED = CmsImages.createIcon("remote_connected.gif");
+       public final static Image WORKSPACE_DISCONNECTED = CmsImages.createIcon("workspace_disconnected.png");
+       public final static Image WORKSPACE_CONNECTED = CmsImages.createIcon("workspace_connected.png");
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/JcrTreeContentProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/JcrTreeContentProvider.java
new file mode 100644 (file)
index 0000000..cc8479f
--- /dev/null
@@ -0,0 +1,82 @@
+package org.argeo.cms.ui.jcr;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.jcr.util.JcrItemsComparator;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * Implementation of the {@code ITreeContentProvider} in order to display a
+ * single JCR node and its children in a tree like structure
+ */
+public class JcrTreeContentProvider implements ITreeContentProvider {
+       private static final long serialVersionUID = -2128326504754297297L;
+       // private Node rootNode;
+       private JcrItemsComparator itemComparator = new JcrItemsComparator();
+
+       /**
+        * Sends back the first level of the Tree. input element must be a single node
+        * object
+        */
+       public Object[] getElements(Object inputElement) {
+               Node rootNode = (Node) inputElement;
+               return childrenNodes(rootNode);
+       }
+
+       public Object[] getChildren(Object parentElement) {
+               return childrenNodes((Node) parentElement);
+       }
+
+       public Object getParent(Object element) {
+               try {
+                       Node node = (Node) element;
+                       if (!node.getPath().equals("/"))
+                               return node.getParent();
+                       else
+                               return null;
+               } catch (RepositoryException e) {
+                       return null;
+               }
+       }
+
+       public boolean hasChildren(Object element) {
+               try {
+                       return ((Node) element).hasNodes();
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot check children existence on " + element, e);
+               }
+       }
+
+       protected Object[] childrenNodes(Node parentNode) {
+               try {
+                       List<Node> children = new ArrayList<Node>();
+                       NodeIterator nit = parentNode.getNodes();
+                       while (nit.hasNext()) {
+                               Node node = nit.nextNode();
+//                             if (node.getName().startsWith("rep:") || node.getName().startsWith("jcr:")
+//                                             || node.getName().startsWith("nt:"))
+//                                     continue nodes;
+                               children.add(node);
+                       }
+                       Node[] arr = children.toArray(new Node[0]);
+                       Arrays.sort(arr, itemComparator);
+                       return arr;
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot list children of " + parentNode, e);
+               }
+       }
+
+       public void dispose() {
+       }
+
+       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/NodeContentProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/NodeContentProvider.java
new file mode 100644 (file)
index 0000000..0625cc8
--- /dev/null
@@ -0,0 +1,175 @@
+package org.argeo.cms.ui.jcr;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.security.Keyring;
+import org.argeo.cms.ui.jcr.model.RepositoriesElem;
+import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * Implementation of the {@code ITreeContentProvider} to display multiple
+ * repository environment in a tree like structure
+ */
+public class NodeContentProvider implements ITreeContentProvider {
+       private static final long serialVersionUID = -4083809398848374403L;
+       final private RepositoryRegister repositoryRegister;
+       final private RepositoryFactory repositoryFactory;
+
+       // Current user session on the default workspace of the argeo Node
+       final private Session userSession;
+       final private Keyring keyring;
+       private boolean sortChildren;
+
+       // Reference for cleaning
+       private SingleJcrNodeElem homeNode = null;
+       private RepositoriesElem repositoriesNode = null;
+
+       // Utils
+       private TreeBrowserComparator itemComparator = new TreeBrowserComparator();
+
+       public NodeContentProvider(Session userSession, Keyring keyring,
+                       RepositoryRegister repositoryRegister,
+                       RepositoryFactory repositoryFactory, Boolean sortChildren) {
+               this.userSession = userSession;
+               this.keyring = keyring;
+               this.repositoryRegister = repositoryRegister;
+               this.repositoryFactory = repositoryFactory;
+               this.sortChildren = sortChildren;
+       }
+
+       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+               if (newInput == null)// dispose
+                       return;
+
+               if (userSession != null) {
+                       Node userHome = CmsJcrUtils.getUserHome(userSession);
+                       if (userHome != null) {
+                               // TODO : find a way to dynamically get alias for the node
+                               if (homeNode != null)
+                                       homeNode.dispose();
+                               homeNode = new SingleJcrNodeElem(null, userHome,
+                                               userSession.getUserID(), CmsConstants.EGO_REPOSITORY);
+                       }
+               }
+               if (repositoryRegister != null) {
+                       if (repositoriesNode != null)
+                               repositoriesNode.dispose();
+                       repositoriesNode = new RepositoriesElem("Repositories",
+                                       repositoryRegister, repositoryFactory, null, userSession,
+                                       keyring);
+               }
+       }
+
+       /**
+        * Sends back the first level of the Tree. Independent from inputElement
+        * that can be null
+        */
+       public Object[] getElements(Object inputElement) {
+               List<Object> objs = new ArrayList<Object>();
+               if (homeNode != null)
+                       objs.add(homeNode);
+               if (repositoriesNode != null)
+                       objs.add(repositoriesNode);
+               return objs.toArray();
+       }
+
+       public Object[] getChildren(Object parentElement) {
+               if (parentElement instanceof TreeParent) {
+                       if (sortChildren) {
+                               Object[] tmpArr = ((TreeParent) parentElement).getChildren();
+                               if (tmpArr == null)
+                                       return new Object[0];
+                               TreeParent[] arr = new TreeParent[tmpArr.length];
+                               for (int i = 0; i < tmpArr.length; i++)
+                                       arr[i] = (TreeParent) tmpArr[i];
+                               Arrays.sort(arr, itemComparator);
+                               return arr;
+                       } else
+                               return ((TreeParent) parentElement).getChildren();
+               } else
+                       return new Object[0];
+       }
+
+       /**
+        * Sets whether the content provider should order the children nodes or not.
+        * It is user duty to call a full refresh of the tree after changing this
+        * parameter.
+        */
+       public void setSortChildren(boolean sortChildren) {
+               this.sortChildren = sortChildren;
+       }
+
+       public Object getParent(Object element) {
+               if (element instanceof TreeParent) {
+                       return ((TreeParent) element).getParent();
+               } else
+                       return null;
+       }
+
+       public boolean hasChildren(Object element) {
+               if (element instanceof RepositoriesElem) {
+                       RepositoryRegister rr = ((RepositoriesElem) element)
+                                       .getRepositoryRegister();
+                       return rr.getRepositories().size() > 0;
+               } else if (element instanceof TreeParent) {
+                       TreeParent tp = (TreeParent) element;
+                       return tp.hasChildren();
+               }
+               return false;
+       }
+
+       public void dispose() {
+               if (homeNode != null)
+                       homeNode.dispose();
+               if (repositoriesNode != null) {
+                       // logs out open sessions
+                       // see https://bugzilla.argeo.org/show_bug.cgi?id=23
+                       repositoriesNode.dispose();
+               }
+       }
+
+       /**
+        * Specific comparator for this view. See specification here:
+        * https://www.argeo.org/bugzilla/show_bug.cgi?id=139
+        */
+       private class TreeBrowserComparator implements Comparator<TreeParent> {
+
+               public int category(TreeParent element) {
+                       if (element instanceof SingleJcrNodeElem) {
+                               Node node = ((SingleJcrNodeElem) element).getNode();
+                               try {
+                                       if (node.isNodeType(NodeType.NT_FOLDER))
+                                               return 5;
+                               } catch (RepositoryException e) {
+                                       // TODO Auto-generated catch block
+                                       e.printStackTrace();
+                               }
+                       }
+                       return 10;
+               }
+
+               public int compare(TreeParent o1, TreeParent o2) {
+                       int cat1 = category(o1);
+                       int cat2 = category(o2);
+
+                       if (cat1 != cat2) {
+                               return cat1 - cat2;
+                       }
+                       return o1.getName().compareTo(o2.getName());
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/NodeLabelProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/NodeLabelProvider.java
new file mode 100644 (file)
index 0000000..a5751c0
--- /dev/null
@@ -0,0 +1,113 @@
+package org.argeo.cms.ui.jcr;
+
+import javax.jcr.NamespaceException;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.ui.jcr.model.RemoteRepositoryElem;
+import org.argeo.cms.ui.jcr.model.RepositoriesElem;
+import org.argeo.cms.ui.jcr.model.RepositoryElem;
+import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
+import org.argeo.cms.ui.jcr.model.WorkspaceElem;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.swt.graphics.Image;
+
+/** Provides reasonable defaults for know JCR types. */
+public class NodeLabelProvider extends ColumnLabelProvider {
+       private static final long serialVersionUID = -3662051696443321843L;
+
+       private final static CmsLog log = CmsLog.getLog(NodeLabelProvider.class);
+
+       public String getText(Object element) {
+               try {
+                       if (element instanceof SingleJcrNodeElem) {
+                               SingleJcrNodeElem sjn = (SingleJcrNodeElem) element;
+                               return getText(sjn.getNode());
+                       } else if (element instanceof Node) {
+                               return getText((Node) element);
+                       } else
+                               return super.getText(element);
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Unexpected JCR error while getting node name.");
+               }
+       }
+
+       protected String getText(Node node) throws RepositoryException {
+               String label = node.getName();
+               StringBuffer mixins = new StringBuffer("");
+               for (NodeType type : node.getMixinNodeTypes())
+                       mixins.append(' ').append(type.getName());
+
+               return label + " [" + node.getPrimaryNodeType().getName() + mixins + "]";
+       }
+
+       @Override
+       public Image getImage(Object element) {
+               if (element instanceof RemoteRepositoryElem) {
+                       if (((RemoteRepositoryElem) element).isConnected())
+                               return JcrImages.REMOTE_CONNECTED;
+                       else
+                               return JcrImages.REMOTE_DISCONNECTED;
+               } else if (element instanceof RepositoryElem) {
+                       if (((RepositoryElem) element).isConnected())
+                               return JcrImages.REPOSITORY_CONNECTED;
+                       else
+                               return JcrImages.REPOSITORY_DISCONNECTED;
+               } else if (element instanceof WorkspaceElem) {
+                       if (((WorkspaceElem) element).isConnected())
+                               return JcrImages.WORKSPACE_CONNECTED;
+                       else
+                               return JcrImages.WORKSPACE_DISCONNECTED;
+               } else if (element instanceof RepositoriesElem) {
+                       return JcrImages.REPOSITORIES;
+               } else if (element instanceof SingleJcrNodeElem) {
+                       Node nodeElem = ((SingleJcrNodeElem) element).getNode();
+                       return getImage(nodeElem);
+
+                       // if (element instanceof Node) {
+                       // return getImage((Node) element);
+                       // } else if (element instanceof WrappedNode) {
+                       // return getImage(((WrappedNode) element).getNode());
+                       // } else if (element instanceof NodesWrapper) {
+                       // return getImage(((NodesWrapper) element).getNode());
+                       // }
+               }
+               // try {
+               // return super.getImage();
+               // } catch (RepositoryException e) {
+               // return null;
+               // }
+               return super.getImage(element);
+       }
+
+       protected Image getImage(Node node) {
+               try {
+                       if (node.getPrimaryNodeType().isNodeType(NodeType.NT_FILE))
+                               return JcrImages.FILE;
+                       else if (node.getPrimaryNodeType().isNodeType(NodeType.NT_FOLDER))
+                               return JcrImages.FOLDER;
+                       else if (node.getPrimaryNodeType().isNodeType(NodeType.NT_RESOURCE))
+                               return JcrImages.BINARY;
+                       try {
+                               // TODO check workspace type?
+                               if (node.getDepth() == 1 && node.hasProperty(Property.JCR_ID))
+                                       return JcrImages.HOME;
+
+                               // optimizes
+//                             if (node.hasProperty(LdapAttrs.uid.property()) && node.isNodeType(NodeTypes.NODE_USER_HOME))
+//                                     return JcrImages.HOME;
+                       } catch (NamespaceException e) {
+                               // node namespace is not registered in this repo
+                       }
+                       return JcrImages.NODE;
+               } catch (RepositoryException e) {
+                       log.warn("Error while retrieving type for " + node + " in order to display corresponding image");
+                       e.printStackTrace();
+                       return null;
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/OsgiRepositoryRegister.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/OsgiRepositoryRegister.java
new file mode 100644 (file)
index 0000000..444350a
--- /dev/null
@@ -0,0 +1,52 @@
+package org.argeo.cms.ui.jcr;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.Repository;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class OsgiRepositoryRegister extends DefaultRepositoryRegister {
+       private final static BundleContext bc = FrameworkUtil.getBundle(OsgiRepositoryRegister.class).getBundleContext();
+       private final ServiceTracker<Repository, Repository> repositoryTracker;
+
+       public OsgiRepositoryRegister() {
+               repositoryTracker = new ServiceTracker<Repository, Repository>(bc, Repository.class, null) {
+
+                       @Override
+                       public Repository addingService(ServiceReference<Repository> reference) {
+
+                               Repository repository = super.addingService(reference);
+                               Map<String, Object> props = new HashMap<>();
+                               for (String key : reference.getPropertyKeys()) {
+                                       props.put(key, reference.getProperty(key));
+                               }
+                               register(repository, props);
+                               return repository;
+                       }
+
+                       @Override
+                       public void removedService(ServiceReference<Repository> reference, Repository service) {
+                               Map<String, Object> props = new HashMap<>();
+                               for (String key : reference.getPropertyKeys()) {
+                                       props.put(key, reference.getProperty(key));
+                               }
+                               unregister(service, props);
+                               super.removedService(reference, service);
+                       }
+
+               };
+       }
+
+       public void init() {
+               repositoryTracker.open();
+       }
+
+       public void destroy() {
+               repositoryTracker.close();
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/PropertiesContentProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/PropertiesContentProvider.java
new file mode 100644 (file)
index 0000000..fd544bb
--- /dev/null
@@ -0,0 +1,42 @@
+package org.argeo.cms.ui.jcr;
+
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.jcr.util.JcrItemsComparator;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/** Simple content provider that displays all properties of a given Node */
+public class PropertiesContentProvider implements IStructuredContentProvider {
+       private static final long serialVersionUID = 5227554668841613078L;
+       private JcrItemsComparator itemComparator = new JcrItemsComparator();
+
+       public void dispose() {
+       }
+
+       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+       }
+
+       public Object[] getElements(Object inputElement) {
+               try {
+                       if (inputElement instanceof Node) {
+                               Set<Property> props = new TreeSet<Property>(itemComparator);
+                               PropertyIterator pit = ((Node) inputElement).getProperties();
+                               while (pit.hasNext())
+                                       props.add(pit.nextProperty());
+                               return props.toArray();
+                       }
+                       return new Object[] {};
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot get element for "
+                                       + inputElement, e);
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/PropertyLabelProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/PropertyLabelProvider.java
new file mode 100644 (file)
index 0000000..37b90f7
--- /dev/null
@@ -0,0 +1,101 @@
+package org.argeo.cms.ui.jcr;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+
+import javax.jcr.Property;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+import org.argeo.cms.ui.CmsUiConstants;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ViewerCell;
+
+/** Default basic label provider for a given JCR Node's properties */
+public class PropertyLabelProvider extends ColumnLabelProvider {
+       private static final long serialVersionUID = -5405794508731390147L;
+
+       // To be able to change column order easily
+       public static final int COLUMN_PROPERTY = 0;
+       public static final int COLUMN_VALUE = 1;
+       public static final int COLUMN_TYPE = 2;
+       public static final int COLUMN_ATTRIBUTES = 3;
+
+       // Utils
+       protected DateFormat timeFormatter = new SimpleDateFormat(CmsUiConstants.DATE_TIME_FORMAT);
+
+       public void update(ViewerCell cell) {
+               Object element = cell.getElement();
+               cell.setText(getColumnText(element, cell.getColumnIndex()));
+       }
+
+       public String getColumnText(Object element, int columnIndex) {
+               try {
+                       if (element instanceof Property) {
+                               Property prop = (Property) element;
+                               if (prop.isMultiple()) {
+                                       switch (columnIndex) {
+                                       case COLUMN_PROPERTY:
+                                               return prop.getName();
+                                       case COLUMN_VALUE:
+                                               // Corresponding values are listed on children
+                                               return "";
+                                       case COLUMN_TYPE:
+                                               return JcrBrowserUtils.getPropertyTypeAsString(prop);
+                                       case COLUMN_ATTRIBUTES:
+                                               return JcrUtils.getPropertyDefinitionAsString(prop);
+                                       }
+                               } else {
+                                       switch (columnIndex) {
+                                       case COLUMN_PROPERTY:
+                                               return prop.getName();
+                                       case COLUMN_VALUE:
+                                               return formatValueAsString(prop.getValue());
+                                       case COLUMN_TYPE:
+                                               return JcrBrowserUtils.getPropertyTypeAsString(prop);
+                                       case COLUMN_ATTRIBUTES:
+                                               return JcrUtils.getPropertyDefinitionAsString(prop);
+                                       }
+                               }
+                       } else if (element instanceof Value) {
+                               Value val = (Value) element;
+                               switch (columnIndex) {
+                               case COLUMN_PROPERTY:
+                                       // Nothing to show
+                                       return "";
+                               case COLUMN_VALUE:
+                                       return formatValueAsString(val);
+                               case COLUMN_TYPE:
+                                       // listed on the parent
+                                       return "";
+                               case COLUMN_ATTRIBUTES:
+                                       // Corresponding attributes are listed on the parent
+                                       return "";
+                               }
+                       }
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Cannot retrieve prop value on " + element, re);
+               }
+               return null;
+       }
+
+       private String formatValueAsString(Value value) {
+               // TODO enhance this method
+               try {
+                       String strValue;
+
+                       if (value.getType() == PropertyType.BINARY)
+                               strValue = "<binary>";
+                       else if (value.getType() == PropertyType.DATE)
+                               strValue = timeFormatter.format(value.getDate().getTime());
+                       else
+                               strValue = value.getString();
+                       return strValue;
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("unexpected error while formatting value", e);
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/RepositoryRegister.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/RepositoryRegister.java
new file mode 100644 (file)
index 0000000..802c756
--- /dev/null
@@ -0,0 +1,16 @@
+package org.argeo.cms.ui.jcr;
+
+import java.util.Map;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryFactory;
+
+/** Allows to register repositories by name. */
+public interface RepositoryRegister extends RepositoryFactory {
+       /**
+        * The registered {@link Repository} as a read-only map. Note that this
+        * method should be called for each access in order to be sure to be up to
+        * date in case repositories have registered/unregistered
+        */
+       public Map<String, Repository> getRepositories();
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/VersionLabelProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/VersionLabelProvider.java
new file mode 100644 (file)
index 0000000..37dfe2b
--- /dev/null
@@ -0,0 +1,33 @@
+package org.argeo.cms.ui.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.version.Version;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+
+/**
+ * Simple wrapping of the ColumnLabelProvider class to provide text display in
+ * order to build a tree for version. The getText() method does not assume that
+ * {@link Version} extends {@link Node} class to respect JCR 2.0 specification
+ * 
+ */
+public class VersionLabelProvider extends ColumnLabelProvider {
+       private static final long serialVersionUID = 5270739851193688238L;
+
+       public String getText(Object element) {
+               try {
+                       if (element instanceof Version) {
+                               Version version = (Version) element;
+                               return version.getName();
+                       } else if (element instanceof Node) {
+                               return ((Node) element).getName();
+                       }
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException(
+                                       "Unexpected error while getting element name", re);
+               }
+               return super.getText(element);
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/MaintainedRepositoryElem.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/MaintainedRepositoryElem.java
new file mode 100644 (file)
index 0000000..d33b33f
--- /dev/null
@@ -0,0 +1,21 @@
+package org.argeo.cms.ui.jcr.model;
+
+import javax.jcr.Repository;
+
+import org.argeo.cms.ux.widgets.TreeParent;
+
+/** Wrap a MaintainedRepository */
+public class MaintainedRepositoryElem extends RepositoryElem {
+
+       public MaintainedRepositoryElem(String alias, Repository repository, TreeParent parent) {
+               super(alias, repository, parent);
+               // if (!(repository instanceof MaintainedRepository)) {
+               // throw new ArgeoException("Repository " + alias
+               // + " is not a maintained repository");
+               // }
+       }
+
+       // protected MaintainedRepository getMaintainedRepository() {
+       // return (MaintainedRepository) getRepository();
+       // }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/RemoteRepositoryElem.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/RemoteRepositoryElem.java
new file mode 100644 (file)
index 0000000..908d1b1
--- /dev/null
@@ -0,0 +1,76 @@
+package org.argeo.cms.ui.jcr.model;
+
+import java.util.Arrays;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import org.argeo.cms.ArgeoNames;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.security.Keyring;
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.argeo.eclipse.ui.EclipseUiException;
+
+/** Root of a remote repository */
+public class RemoteRepositoryElem extends RepositoryElem {
+       private final Keyring keyring;
+       /**
+        * A session of the logged in user on the default workspace of the node
+        * repository.
+        */
+       private final Session userSession;
+       private final String remoteNodePath;
+
+       private final RepositoryFactory repositoryFactory;
+       private final String uri;
+
+       public RemoteRepositoryElem(String alias, RepositoryFactory repositoryFactory, String uri, TreeParent parent,
+                       Session userSession, Keyring keyring, String remoteNodePath) {
+               super(alias, null, parent);
+               this.repositoryFactory = repositoryFactory;
+               this.uri = uri;
+               this.keyring = keyring;
+               this.userSession = userSession;
+               this.remoteNodePath = remoteNodePath;
+       }
+
+       @Override
+       protected Session repositoryLogin(String workspaceName) throws RepositoryException {
+               Node remoteRepository = userSession.getNode(remoteNodePath);
+               String userID = remoteRepository.getProperty(ArgeoNames.ARGEO_USER_ID).getString();
+               if (userID.trim().equals("")) {
+                       return getRepository().login(workspaceName);
+               } else {
+                       String pwdPath = remoteRepository.getPath() + '/' + ArgeoNames.ARGEO_PASSWORD;
+                       char[] password = keyring.getAsChars(pwdPath);
+                       try {
+                               SimpleCredentials credentials = new SimpleCredentials(userID, password);
+                               return getRepository().login(credentials, workspaceName);
+                       } finally {
+                               Arrays.fill(password, 0, password.length, ' ');
+                       }
+               }
+       }
+
+       @Override
+       public Repository getRepository() {
+               if (repository == null)
+                       repository = CmsJcrUtils.getRepositoryByUri(repositoryFactory, uri);
+               return super.getRepository();
+       }
+
+       public void remove() {
+               try {
+                       Node remoteNode = userSession.getNode(remoteNodePath);
+                       remoteNode.remove();
+                       remoteNode.getSession().save();
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot remove " + remoteNodePath, e);
+               }
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/RepositoriesElem.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/RepositoriesElem.java
new file mode 100644 (file)
index 0000000..742800b
--- /dev/null
@@ -0,0 +1,112 @@
+package org.argeo.cms.ui.jcr.model;
+
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
+
+import org.argeo.cms.ArgeoNames;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.security.Keyring;
+import org.argeo.cms.ui.jcr.RepositoryRegister;
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
+
+/**
+ * UI Tree component that implements the Argeo abstraction of a
+ * {@link RepositoryFactory} that enable a user to "mount" various repositories
+ * in a single Tree like View. It is usually meant to be at the root of the UI
+ * Tree and thus {@link getParent()} method will return null.
+ * 
+ * The {@link RepositoryFactory} is injected at instantiation time and must be
+ * use get or register new {@link Repository} objects upon which a reference is
+ * kept here.
+ */
+
+public class RepositoriesElem extends TreeParent implements ArgeoNames {
+       private final RepositoryRegister repositoryRegister;
+       private final RepositoryFactory repositoryFactory;
+
+       /**
+        * A session of the logged in user on the default workspace of the node
+        * repository.
+        */
+       private final Session userSession;
+       private final Keyring keyring;
+
+       public RepositoriesElem(String name, RepositoryRegister repositoryRegister, RepositoryFactory repositoryFactory,
+                       TreeParent parent, Session userSession, Keyring keyring) {
+               super(name);
+               this.repositoryRegister = repositoryRegister;
+               this.repositoryFactory = repositoryFactory;
+               this.userSession = userSession;
+               this.keyring = keyring;
+       }
+
+       /**
+        * Override normal behavior to initialize the various repositories only at
+        * request time
+        */
+       @Override
+       public synchronized Object[] getChildren() {
+               if (isLoaded()) {
+                       return super.getChildren();
+               } else {
+                       // initialize current object
+                       Map<String, Repository> refRepos = repositoryRegister.getRepositories();
+                       for (String name : refRepos.keySet()) {
+                               Repository repository = refRepos.get(name);
+                               // if (repository instanceof MaintainedRepository)
+                               // super.addChild(new MaintainedRepositoryElem(name,
+                               // repository, this));
+                               // else
+                               super.addChild(new RepositoryElem(name, repository, this));
+                       }
+
+                       // remote
+                       if (keyring != null) {
+                               try {
+                                       addRemoteRepositories(keyring);
+                               } catch (RepositoryException e) {
+                                       throw new EclipseUiException("Cannot browse remote repositories", e);
+                               }
+                       }
+                       return super.getChildren();
+               }
+       }
+
+       protected void addRemoteRepositories(Keyring jcrKeyring) throws RepositoryException {
+               Node userHome = CmsJcrUtils.getUserHome(userSession);
+               if (userHome != null && userHome.hasNode(ARGEO_REMOTE)) {
+                       NodeIterator it = userHome.getNode(ARGEO_REMOTE).getNodes();
+                       while (it.hasNext()) {
+                               Node remoteNode = it.nextNode();
+                               String uri = remoteNode.getProperty(ARGEO_URI).getString();
+                               try {
+                                       RemoteRepositoryElem remoteRepositoryNode = new RemoteRepositoryElem(remoteNode.getName(),
+                                                       repositoryFactory, uri, this, userSession, jcrKeyring, remoteNode.getPath());
+                                       super.addChild(remoteRepositoryNode);
+                               } catch (Exception e) {
+                                       ErrorFeedback.show("Cannot add remote repository " + remoteNode, e);
+                               }
+                       }
+               }
+       }
+
+       public void registerNewRepository(String alias, Repository repository) {
+               // TODO: implement this
+               // Create a new RepositoryNode Object
+               // add it
+               // super.addChild(new RepositoriesNode(...));
+       }
+
+       /** Returns the {@link RepositoryRegister} wrapped by this object. */
+       public RepositoryRegister getRepositoryRegister() {
+               return repositoryRegister;
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/RepositoryElem.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/RepositoryElem.java
new file mode 100644 (file)
index 0000000..296c369
--- /dev/null
@@ -0,0 +1,98 @@
+package org.argeo.cms.ui.jcr.model;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.jcr.JcrUtils;
+
+/**
+ * UI Tree component that wraps a JCR {@link Repository}. It also keeps a
+ * reference to its parent Tree Ui component; typically the unique
+ * {@link RepositoriesElem} object of the current view to enable bi-directionnal
+ * browsing in the tree.
+ */
+
+public class RepositoryElem extends TreeParent {
+       private String alias;
+       protected Repository repository;
+       private Session defaultSession = null;
+
+       /** Create a new repository with distinct name and alias */
+       public RepositoryElem(String alias, Repository repository, TreeParent parent) {
+               super(alias);
+               this.repository = repository;
+               setParent(parent);
+               this.alias = alias;
+       }
+
+       public void login() {
+               try {
+                       defaultSession = repositoryLogin(CmsConstants.SYS_WORKSPACE);
+                       String[] wkpNames = defaultSession.getWorkspace().getAccessibleWorkspaceNames();
+                       for (String wkpName : wkpNames) {
+                               if (wkpName.equals(defaultSession.getWorkspace().getName()))
+                                       addChild(new WorkspaceElem(this, wkpName, defaultSession));
+                               else
+                                       addChild(new WorkspaceElem(this, wkpName));
+                       }
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot connect to repository " + alias, e);
+               }
+       }
+
+       public synchronized void logout() {
+               for (Object child : getChildren()) {
+                       if (child instanceof WorkspaceElem)
+                               ((WorkspaceElem) child).logout();
+               }
+               clearChildren();
+               JcrUtils.logoutQuietly(defaultSession);
+               defaultSession = null;
+       }
+
+       /**
+        * Actual call to the {@link Repository#login(javax.jcr.Credentials, String)}
+        * method. To be overridden.
+        */
+       protected Session repositoryLogin(String workspaceName) throws RepositoryException {
+               return repository.login(workspaceName);
+       }
+
+       public String[] getAccessibleWorkspaceNames() {
+               try {
+                       return defaultSession.getWorkspace().getAccessibleWorkspaceNames();
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot retrieve workspace names", e);
+               }
+       }
+
+       public void createWorkspace(String workspaceName) {
+               if (!isConnected())
+                       login();
+               try {
+                       defaultSession.getWorkspace().createWorkspace(workspaceName);
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot create workspace", e);
+               }
+       }
+
+       /** returns the {@link Repository} referenced by the current UI Node */
+       public Repository getRepository() {
+               return repository;
+       }
+
+       public String getAlias() {
+               return alias;
+       }
+
+       public Boolean isConnected() {
+               if (defaultSession != null && defaultSession.isLive())
+                       return true;
+               else
+                       return false;
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/SingleJcrNodeElem.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/SingleJcrNodeElem.java
new file mode 100644 (file)
index 0000000..a2584a5
--- /dev/null
@@ -0,0 +1,84 @@
+package org.argeo.cms.ui.jcr.model;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Workspace;
+
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.argeo.eclipse.ui.EclipseUiException;
+
+/**
+ * UI Tree component. Wraps a node of a JCR {@link Workspace}. It also keeps a
+ * reference to its parent node that can either be a {@link WorkspaceElem}, a
+ * {@link SingleJcrNodeElem} or null if the node is "mounted" as the root of the
+ * UI tree.
+ */
+public class SingleJcrNodeElem extends TreeParent {
+
+       private final Node node;
+       private String alias = null;
+
+       /** Creates a new UiNode in the UI Tree */
+       public SingleJcrNodeElem(TreeParent parent, Node node, String name) {
+               super(name);
+               setParent(parent);
+               this.node = node;
+       }
+
+       /**
+        * Creates a new UiNode in the UI Tree, keeping a reference to the alias of
+        * the corresponding repository in the current UI environment. It is useful
+        * to be able to mount nodes as roots of the UI tree.
+        */
+       public SingleJcrNodeElem(TreeParent parent, Node node, String name, String alias) {
+               super(name);
+               setParent(parent);
+               this.node = node;
+               this.alias = alias;
+       }
+
+       /** Returns the node wrapped by the current UI object */
+       public Node getNode() {
+               return node;
+       }
+
+       protected String getRepositoryAlias() {
+               return alias;
+       }
+
+       /**
+        * Overrides normal behaviour to initialise children only when first
+        * requested
+        */
+       @Override
+       public synchronized Object[] getChildren() {
+               if (isLoaded()) {
+                       return super.getChildren();
+               } else {
+                       // initialize current object
+                       try {
+                               NodeIterator ni = node.getNodes();
+                               while (ni.hasNext()) {
+                                       Node curNode = ni.nextNode();
+                                       addChild(new SingleJcrNodeElem(this, curNode, curNode.getName()));
+                               }
+                               return super.getChildren();
+                       } catch (RepositoryException re) {
+                               throw new EclipseUiException("Cannot initialize SingleJcrNode children", re);
+                       }
+               }
+       }
+
+       @Override
+       public boolean hasChildren() {
+               try {
+                       if (node.getSession().isLive())
+                               return node.hasNodes();
+                       else
+                               return false;
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Cannot check children node existence", re);
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/WorkspaceElem.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/WorkspaceElem.java
new file mode 100644 (file)
index 0000000..2d78666
--- /dev/null
@@ -0,0 +1,117 @@
+package org.argeo.cms.ui.jcr.model;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+// import javax.jcr.Workspace;
+import javax.jcr.Workspace;
+
+import org.argeo.cms.ux.widgets.TreeParent;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.jcr.JcrUtils;
+
+/**
+ * UI Tree component. Wraps the root node of a JCR {@link Workspace}. It also
+ * keeps a reference to its parent {@link RepositoryElem}, to be able to
+ * retrieve alias of the current used repository
+ */
+public class WorkspaceElem extends TreeParent {
+       private Session session = null;
+
+       public WorkspaceElem(RepositoryElem parent, String name) {
+               this(parent, name, null);
+       }
+
+       public WorkspaceElem(RepositoryElem parent, String name, Session session) {
+               super(name);
+               this.session = session;
+               setParent(parent);
+       }
+
+       public synchronized Session getSession() {
+               return session;
+       }
+
+       public synchronized Node getRootNode() {
+               try {
+                       if (session != null)
+                               return session.getRootNode();
+                       else
+                               return null;
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot get root node of workspace " + getName(), e);
+               }
+       }
+
+       public synchronized void login() {
+               try {
+                       session = ((RepositoryElem) getParent()).repositoryLogin(getName());
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot connect to repository " + getName(), e);
+               }
+       }
+
+       public Boolean isConnected() {
+               if (session != null && session.isLive())
+                       return true;
+               else
+                       return false;
+       }
+
+       @Override
+       public synchronized void dispose() {
+               logout();
+               super.dispose();
+       }
+
+       /** Logouts the session, does not nothing if there is no live session. */
+       public synchronized void logout() {
+               clearChildren();
+               JcrUtils.logoutQuietly(session);
+               session = null;
+       }
+
+       @Override
+       public synchronized boolean hasChildren() {
+               try {
+                       if (isConnected())
+                               try {
+                                       return session.getRootNode().hasNodes();
+                               } catch (AccessDeniedException e) {
+                                       // current user may not have access to the root node
+                                       return false;
+                               }
+                       else
+                               return false;
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Unexpected error while checking children node existence", re);
+               }
+       }
+
+       /** Override normal behaviour to initialize display of the workspace */
+       @Override
+       public synchronized Object[] getChildren() {
+               if (isLoaded()) {
+                       return super.getChildren();
+               } else {
+                       // initialize current object
+                       try {
+                               Node rootNode;
+                               if (session == null)
+                                       return null;
+                               else
+                                       rootNode = session.getRootNode();
+                               NodeIterator ni = rootNode.getNodes();
+                               while (ni.hasNext()) {
+                                       Node node = ni.nextNode();
+                                       addChild(new SingleJcrNodeElem(this, node, node.getName()));
+                               }
+                               return super.getChildren();
+                       } catch (RepositoryException e) {
+                               throw new EclipseUiException("Cannot initialize WorkspaceNode UI object." + getName(), e);
+                       }
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/package-info.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/model/package-info.java
new file mode 100644 (file)
index 0000000..8f54744
--- /dev/null
@@ -0,0 +1,2 @@
+/** Model for SWT/JFace JCR components. */
+package org.argeo.cms.ui.jcr.model;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/package-info.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/jcr/package-info.java
new file mode 100644 (file)
index 0000000..26ae330
--- /dev/null
@@ -0,0 +1,2 @@
+/** SWT/JFace JCR components. */
+package org.argeo.cms.ui.jcr;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/package-info.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/package-info.java
new file mode 100644 (file)
index 0000000..82fdee7
--- /dev/null
@@ -0,0 +1,2 @@
+/** SWT/JFace components for Argeo CMS. */
+package org.argeo.cms.ui;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/CmsLink.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/CmsLink.java
new file mode 100644 (file)
index 0000000..e91f9ba
--- /dev/null
@@ -0,0 +1,282 @@
+package org.argeo.cms.ui.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.CmsStyle;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.jcr.JcrException;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.service.ResourceManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.osgi.framework.BundleContext;
+
+/** A link to an internal or external location. */
+public class CmsLink implements CmsUiProvider {
+       private final static CmsLog log = CmsLog.getLog(CmsLink.class);
+       private BundleContext bundleContext;
+
+       private String label;
+       private String style;
+       private String target;
+       private String image;
+       private boolean openNew = false;
+       private MouseListener mouseListener;
+
+       private int horizontalAlignment = SWT.CENTER;
+       private int verticalAlignment = SWT.CENTER;
+
+       private String loggedInLabel = null;
+       private String loggedInTarget = null;
+
+       // internal
+       // private Boolean isUrl = false;
+       private Integer imageWidth, imageHeight;
+
+       public CmsLink() {
+               super();
+       }
+
+       public CmsLink(String label, String target) {
+               this(label, target, (String) null);
+       }
+
+       public CmsLink(String label, String target, CmsStyle style) {
+               this(label, target, style != null ? style.style() : null);
+       }
+
+       public CmsLink(String label, String target, String style) {
+               super();
+               this.label = label;
+               this.target = target;
+               this.style = style;
+               init();
+       }
+
+       public void init() {
+               if (image != null) {
+                       ImageData image = loadImage();
+                       if (imageHeight == null && imageWidth == null) {
+                               imageWidth = image.width;
+                               imageHeight = image.height;
+                       } else if (imageHeight == null) {
+                               imageHeight = (imageWidth * image.height) / image.width;
+                       } else if (imageWidth == null) {
+                               imageWidth = (imageHeight * image.width) / image.height;
+                       }
+               }
+       }
+
+       /** @return {@link Composite} with a single {@link Label} child. */
+       @Override
+       public Control createUi(final Composite parent, Node context) {
+//             if (image != null && (imageWidth == null || imageHeight == null)) {
+//                     throw new CmsException("Image is not properly configured."
+//                                     + " Make sure bundleContext property is set and init() method has been called.");
+//             }
+
+               Composite comp = new Composite(parent, SWT.NONE);
+               comp.setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+               Label link = new Label(comp, SWT.NONE);
+               CmsSwtUtils.markup(link);
+               GridData layoutData = new GridData(horizontalAlignment, verticalAlignment, false, false);
+               if (image != null) {
+                       if (imageHeight != null)
+                               layoutData.heightHint = imageHeight;
+                       if (label == null)
+                               if (imageWidth != null)
+                                       layoutData.widthHint = imageWidth;
+               }
+
+               link.setLayoutData(layoutData);
+               CmsSwtUtils.style(comp, style != null ? style : getDefaultStyle());
+               CmsSwtUtils.style(link, style != null ? style : getDefaultStyle());
+
+               // label
+               StringBuilder labelText = new StringBuilder();
+               if (loggedInTarget != null && isLoggedIn()) {
+                       labelText.append("<a style='color:inherit;text-decoration:inherit;' href=\"");
+                       if (loggedInTarget.equals("")) {
+                               try {
+                                       Node homeNode = CmsJcrUtils.getUserHome(context.getSession());
+                                       String homePath = homeNode.getPath();
+                                       labelText.append("/#" + homePath);
+                               } catch (RepositoryException e) {
+                                       throw new JcrException("Cannot get home path", e);
+                               }
+                       } else {
+                               labelText.append(loggedInTarget);
+                       }
+                       labelText.append("\">");
+               } else if (target != null) {
+                       labelText.append("<a style='color:inherit;text-decoration:inherit;' href='");
+                       labelText.append(target).append("'");
+                       if (openNew) {
+                               labelText.append(" target='_blank'");
+                       }
+                       labelText.append(">");
+               }
+               if (image != null) {
+                       registerImageIfNeeded();
+                       String imageLocation = RWT.getResourceManager().getLocation(image);
+                       labelText.append("<img");
+                       if (imageWidth != null)
+                               labelText.append(" width='").append(imageWidth).append('\'');
+                       if (imageHeight != null)
+                               labelText.append(" height='").append(imageHeight).append('\'');
+                       labelText.append(" src=\"").append(imageLocation).append("\"/>");
+
+               }
+
+               if (loggedInLabel != null && isLoggedIn()) {
+                       labelText.append(' ').append(loggedInLabel);
+               } else if (label != null) {
+                       labelText.append(' ').append(label);
+               }
+
+               if ((loggedInTarget != null && isLoggedIn()) || target != null)
+                       labelText.append("</a>");
+
+               link.setText(labelText.toString());
+
+               if (mouseListener != null)
+                       link.addMouseListener(mouseListener);
+
+               return comp;
+       }
+
+       private void registerImageIfNeeded() {
+               ResourceManager resourceManager = RWT.getResourceManager();
+               if (!resourceManager.isRegistered(image)) {
+                       URL res = getImageUrl();
+                       try (InputStream inputStream = res.openStream()) {
+                               resourceManager.register(image, inputStream);
+                               if (log.isTraceEnabled())
+                                       log.trace("Registered image " + image);
+                       } catch (IOException e) {
+                               throw new RuntimeException("Cannot load image " + image, e);
+                       }
+               }
+       }
+
+       private ImageData loadImage() {
+               URL url = getImageUrl();
+               ImageData result = null;
+               try (InputStream inputStream = url.openStream()) {
+                       result = new ImageData(inputStream);
+                       if (log.isTraceEnabled())
+                               log.trace("Loaded image " + image);
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot load image " + image, e);
+               }
+               return result;
+       }
+
+       private URL getImageUrl() {
+               URL url;
+               try {
+                       // pure URL
+                       url = new URL(image);
+               } catch (MalformedURLException e1) {
+                       url = bundleContext.getBundle().getResource(image);
+               }
+
+               if (url == null)
+                       throw new IllegalStateException("No image " + image + " available.");
+
+               return url;
+       }
+
+       public void setBundleContext(BundleContext bundleContext) {
+               this.bundleContext = bundleContext;
+       }
+
+       public void setLabel(String label) {
+               this.label = label;
+       }
+
+       public void setStyle(String style) {
+               this.style = style;
+       }
+
+       /** @deprecated Use {@link #setStyle(String)} instead. */
+       @Deprecated
+       public void setCustom(String custom) {
+               this.style = custom;
+       }
+
+       public void setTarget(String target) {
+               this.target = target;
+               // try {
+               // new URL(target);
+               // isUrl = true;
+               // } catch (MalformedURLException e1) {
+               // isUrl = false;
+               // }
+       }
+
+       public void setImage(String image) {
+               this.image = image;
+       }
+
+       public void setLoggedInLabel(String loggedInLabel) {
+               this.loggedInLabel = loggedInLabel;
+       }
+
+       public void setLoggedInTarget(String loggedInTarget) {
+               this.loggedInTarget = loggedInTarget;
+       }
+
+       public void setMouseListener(MouseListener mouseListener) {
+               this.mouseListener = mouseListener;
+       }
+
+       public void setvAlign(String vAlign) {
+               if ("bottom".equals(vAlign)) {
+                       verticalAlignment = SWT.BOTTOM;
+               } else if ("top".equals(vAlign)) {
+                       verticalAlignment = SWT.TOP;
+               } else if ("center".equals(vAlign)) {
+                       verticalAlignment = SWT.CENTER;
+               } else {
+                       throw new IllegalArgumentException(
+                                       "Unsupported vertical alignment " + vAlign + " (must be: top, bottom or center)");
+               }
+       }
+
+       protected boolean isLoggedIn() {
+               return !CurrentUser.isAnonymous();
+       }
+
+       public void setImageWidth(Integer imageWidth) {
+               this.imageWidth = imageWidth;
+       }
+
+       public void setImageHeight(Integer imageHeight) {
+               this.imageHeight = imageHeight;
+       }
+
+       public void setOpenNew(boolean openNew) {
+               this.openNew = openNew;
+       }
+
+       protected String getDefaultStyle() {
+               return SimpleStyle.link.name();
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/CmsPane.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/CmsPane.java
new file mode 100644 (file)
index 0000000..fc0c821
--- /dev/null
@@ -0,0 +1,49 @@
+package org.argeo.cms.ui.util;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/** The main pane of a CMS display, with QA and support areas. */
+public class CmsPane {
+
+       private Composite mainArea;
+       private Composite qaArea;
+       private Composite supportArea;
+
+       public CmsPane(Composite parent, int style) {
+               parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
+
+//             qaArea = new Composite(parent, SWT.NONE);
+//             qaArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+//             RowLayout qaLayout = new RowLayout();
+//             qaLayout.spacing = 0;
+//             qaArea.setLayout(qaLayout);
+
+               mainArea = new Composite(parent, SWT.NONE);
+               mainArea.setLayout(new GridLayout());
+               mainArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+//             supportArea = new Composite(parent, SWT.NONE);
+//             supportArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+//             RowLayout supportLayout = new RowLayout();
+//             supportLayout.spacing = 0;
+//             supportArea.setLayout(supportLayout);
+       }
+
+       public Composite getMainArea() {
+               return mainArea;
+       }
+
+       public Composite getQaArea() {
+               return qaArea;
+       }
+
+       public Composite getSupportArea() {
+               return supportArea;
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java
new file mode 100644 (file)
index 0000000..7cc611c
--- /dev/null
@@ -0,0 +1,192 @@
+package org.argeo.cms.ui.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.api.cms.ux.CmsView;
+import org.argeo.cms.jcr.CmsJcrUtils;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiConstants;
+import org.argeo.cms.ux.AbstractImageManager;
+import org.argeo.cms.ux.CmsUxUtils;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.service.ResourceManager;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.layout.RowData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Table;
+
+/** Static utilities for the CMS framework. */
+public class CmsUiUtils {
+       // private final static Log log = LogFactory.getLog(CmsUiUtils.class);
+
+       /*
+        * CMS VIEW
+        */
+
+       /**
+        * The CMS view related to this display, or null if none is available from this
+        * call.
+        * 
+        * @deprecated Use {@link CmsSwtUtils#getCmsView(Composite)} instead.
+        */
+       @Deprecated
+       public static CmsView getCmsView() {
+//             return UiContext.getData(CmsView.class.getName());
+               return CmsSwtUtils.getCmsView(Display.getCurrent().getActiveShell());
+       }
+
+       public static StringBuilder getServerBaseUrl(HttpServletRequest request) {
+               try {
+                       URL url = new URL(request.getRequestURL().toString());
+                       StringBuilder buf = new StringBuilder();
+                       buf.append(url.getProtocol()).append("://").append(url.getHost());
+                       if (url.getPort() != -1)
+                               buf.append(':').append(url.getPort());
+                       return buf;
+               } catch (MalformedURLException e) {
+                       throw new IllegalArgumentException("Cannot extract server base URL from " + request.getRequestURL(), e);
+               }
+       }
+
+       //
+       public static String getDataUrl(Node node, HttpServletRequest request) {
+               try {
+                       StringBuilder buf = getServerBaseUrl(request);
+                       buf.append(getDataPath(node));
+                       return new URL(buf.toString()).toString();
+               } catch (MalformedURLException e) {
+                       throw new IllegalArgumentException("Cannot build data URL for " + node, e);
+               }
+       }
+
+       /** A path in the node repository */
+       public static String getDataPath(Node node) {
+               return getDataPath(CmsConstants.EGO_REPOSITORY, node);
+       }
+
+       public static String getDataPath(String cn, Node node) {
+               return CmsJcrUtils.getDataPath(cn, node);
+       }
+
+       /** Clean reserved URL characters for use in HTTP links. */
+       public static String getDataPathForUrl(Node node) {
+               return CmsSwtUtils.cleanPathForUrl(getDataPath(node));
+       }
+
+       /** @deprecated Use rowData16px() instead. GridData should not be reused. */
+       @Deprecated
+       public static RowData ROW_DATA_16px = new RowData(16, 16);
+
+       
+
+       /*
+        * FORM LAYOUT
+        */
+
+       
+
+       @Deprecated
+       public static void setItemHeight(Table table, int height) {
+               table.setData(CmsUiConstants.ITEM_HEIGHT, height);
+       }
+
+       //
+       // JCR
+       //
+       public static Node getOrAddEmptyFile(Node parent, Enum<?> child) throws RepositoryException {
+               if (has(parent, child))
+                       return child(parent, child);
+               return JcrUtils.copyBytesAsFile(parent, child.name(), new byte[0]);
+       }
+
+       public static Node child(Node parent, Enum<?> en) throws RepositoryException {
+               return parent.getNode(en.name());
+       }
+
+       public static Boolean has(Node parent, Enum<?> en) throws RepositoryException {
+               return parent.hasNode(en.name());
+       }
+
+       public static Node getOrAdd(Node parent, Enum<?> en) throws RepositoryException {
+               return getOrAdd(parent, en, null);
+       }
+
+       public static Node getOrAdd(Node parent, Enum<?> en, String primaryType) throws RepositoryException {
+               if (has(parent, en))
+                       return child(parent, en);
+               else if (primaryType == null)
+                       return parent.addNode(en.name());
+               else
+                       return parent.addNode(en.name(), primaryType);
+       }
+
+       // IMAGES
+
+       public static String img(Node fileNode, String width, String height) {
+               return img(null, fileNode, width, height);
+       }
+
+       public static String img(String serverBase, Node fileNode, String width, String height) {
+//             String src = (serverBase != null ? serverBase : "") + NodeUtils.getDataPath(fileNode);
+               String src;
+               src = (serverBase != null ? serverBase : "") + getDataPathForUrl(fileNode);
+               return CmsUxUtils.imgBuilder(src, width, height).append("/>").toString();
+       }
+
+       public static String noImg(Cms2DSize size) {
+               ResourceManager rm = RWT.getResourceManager();
+               return CmsUxUtils.img(rm.getLocation(AbstractImageManager.NO_IMAGE), size);
+       }
+
+       public static String noImg() {
+               return noImg(AbstractImageManager.NO_IMAGE_SIZE);
+       }
+
+       public static Image noImage(Cms2DSize size) {
+               ResourceManager rm = RWT.getResourceManager();
+               InputStream in = null;
+               try {
+                       in = rm.getRegisteredContent(AbstractImageManager.NO_IMAGE);
+                       ImageData id = new ImageData(in);
+                       ImageData scaled = id.scaledTo(size.getWidth(), size.getHeight());
+                       Image image = new Image(Display.getCurrent(), scaled);
+                       return image;
+               } finally {
+                       try {
+                               in.close();
+                       } catch (IOException e) {
+                               // silent
+                       }
+               }
+       }
+
+       /** Lorem ipsum text to be used during development. */
+       public final static String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
+                       + " Etiam eleifend hendrerit sem, ac ultricies massa ornare ac."
+                       + " Cras aliquam sodales risus, vitae varius lacus molestie quis."
+                       + " Vivamus consequat, leo id lacinia volutpat, eros diam efficitur urna, finibus interdum risus turpis at nisi."
+                       + " Curabitur vulputate nulla quis scelerisque fringilla. Integer consectetur turpis id lobortis accumsan."
+                       + " Pellentesque commodo turpis ac diam ultricies dignissim."
+                       + " Curabitur sit amet dolor volutpat lacus aliquam ornare quis sed velit."
+                       + " Integer varius quis est et tristique."
+                       + " Suspendisse pharetra porttitor purus, eget condimentum magna."
+                       + " Duis vitae turpis eros. Sed tincidunt lacinia rutrum."
+                       + " Aliquam velit velit, rutrum ut augue sed, condimentum lacinia augue.";
+
+       /** Singleton. */
+       private CmsUiUtils() {
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/DefaultImageManager.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/DefaultImageManager.java
new file mode 100644 (file)
index 0000000..b431fc3
--- /dev/null
@@ -0,0 +1,133 @@
+package org.argeo.cms.ui.util;
+
+import static javax.jcr.Node.JCR_CONTENT;
+import static javax.jcr.Property.JCR_DATA;
+import static javax.jcr.nodetype.NodeType.NT_FILE;
+import static javax.jcr.nodetype.NodeType.NT_RESOURCE;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import javax.jcr.Binary;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.cms.swt.AbstractSwtImageManager;
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.service.ResourceManager;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.widgets.Display;
+
+/** Manages only public images so far. */
+public class DefaultImageManager extends AbstractSwtImageManager<Node> {
+       private final static CmsLog log = CmsLog.getLog(DefaultImageManager.class);
+
+       /** @return null if not available */
+       @Override
+       public String getImageUrl(Node node) {
+               return CmsUiUtils.getDataPathForUrl(node);
+       }
+
+       protected String getResourceName(Node node) {
+               try {
+                       String workspace = node.getSession().getWorkspace().getName();
+                       if (node.hasNode(JCR_CONTENT))
+                               return workspace + '_' + node.getNode(JCR_CONTENT).getIdentifier();
+                       else
+                               return workspace + '_' + node.getIdentifier();
+               } catch (RepositoryException e) {
+                       throw new JcrException(e);
+               }
+       }
+
+       public Binary getImageBinary(Node node) {
+               try {
+                       if (node.isNodeType(NT_FILE)) {
+                               return node.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary();
+                       } else {
+                               return null;
+                       }
+               } catch (RepositoryException e) {
+                       throw new JcrException(e);
+               }
+       }
+
+       public Image getSwtImage(Node node) {
+               InputStream inputStream = null;
+               Binary binary = getImageBinary(node);
+               if (binary == null)
+                       return null;
+               try {
+                       inputStream = binary.getStream();
+                       return new Image(Display.getCurrent(), inputStream);
+               } catch (RepositoryException e) {
+                       throw new JcrException(e);
+               } finally {
+                       IOUtils.closeQuietly(inputStream);
+                       JcrUtils.closeQuietly(binary);
+               }
+       }
+
+       @Override
+       public String uploadImage(Node context, Node parentNode, String fileName, InputStream in, String contentType) {
+               InputStream inputStream = null;
+               try {
+                       String previousResourceName = null;
+                       if (parentNode.hasNode(fileName)) {
+                               Node node = parentNode.getNode(fileName);
+                               previousResourceName = getResourceName(node);
+                               if (node.hasNode(JCR_CONTENT)) {
+                                       node.getNode(JCR_CONTENT).remove();
+                                       node.addNode(JCR_CONTENT, NT_RESOURCE);
+                               }
+                       }
+
+                       byte[] arr = IOUtils.toByteArray(in);
+                       Node fileNode = JcrUtils.copyBytesAsFile(parentNode, fileName, arr);
+                       inputStream = new ByteArrayInputStream(arr);
+                       ImageData id = new ImageData(inputStream);
+                       processNewImageFile(context, fileNode, id);
+
+                       String mime = contentType != null ? contentType : Files.probeContentType(Paths.get(fileName));
+                       if (mime != null) {
+                               fileNode.getNode(JCR_CONTENT).setProperty(Property.JCR_MIMETYPE, mime);
+                       }
+                       fileNode.getSession().save();
+
+                       // reset resource manager
+                       ResourceManager resourceManager = RWT.getResourceManager();
+                       if (previousResourceName != null && resourceManager.isRegistered(previousResourceName)) {
+                               resourceManager.unregister(previousResourceName);
+                               if (log.isDebugEnabled())
+                                       log.debug("Unregistered image " + previousResourceName);
+                       }
+                       return CmsUiUtils.getDataPath(fileNode);
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot upload image " + fileName + " in " + parentNode, e);
+               } catch (RepositoryException e) {
+                       throw new JcrException(e);
+               } finally {
+                       IOUtils.closeQuietly(inputStream);
+               }
+       }
+
+       /** Does nothing by default. */
+       protected void processNewImageFile(Node context, Node fileNode, ImageData id)
+                       throws RepositoryException, IOException {
+       }
+
+       @Override
+       protected String noImg(Cms2DSize size) {
+               return CmsUiUtils.noImg(size);
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/MenuLink.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/MenuLink.java
new file mode 100644 (file)
index 0000000..284d2bd
--- /dev/null
@@ -0,0 +1,22 @@
+package org.argeo.cms.ui.util;
+
+import org.argeo.cms.swt.CmsStyles;
+
+/**
+ * Convenience class setting the custom style {@link CmsStyles#CMS_MENU_LINK} on
+ * a {@link CmsLink} when simple menus are used.
+ */
+public class MenuLink extends CmsLink {
+       public MenuLink() {
+               setCustom(CmsStyles.CMS_MENU_LINK);
+       }
+
+       public MenuLink(String label, String target, String custom) {
+               super(label, target, custom);
+       }
+
+       public MenuLink(String label, String target) {
+               super(label, target, CmsStyles.CMS_MENU_LINK);
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SimpleCmsHeader.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SimpleCmsHeader.java
new file mode 100644 (file)
index 0000000..ab6a29f
--- /dev/null
@@ -0,0 +1,97 @@
+package org.argeo.cms.ui.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.swt.CmsStyles;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** A header in three parts */
+public class SimpleCmsHeader implements CmsUiProvider {
+       private List<CmsUiProvider> lead = new ArrayList<CmsUiProvider>();
+       private List<CmsUiProvider> center = new ArrayList<CmsUiProvider>();
+       private List<CmsUiProvider> end = new ArrayList<CmsUiProvider>();
+
+       private Boolean subPartsSameWidth = false;
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               Composite header = new Composite(parent, SWT.NONE);
+               header.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_HEADER);
+               header.setBackgroundMode(SWT.INHERIT_DEFAULT);
+               header.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(3, false)));
+
+               configurePart(context, header, lead);
+               configurePart(context, header, center);
+               configurePart(context, header, end);
+               return header;
+       }
+
+       protected void configurePart(Node context, Composite parent, List<CmsUiProvider> partProviders)
+                       throws RepositoryException {
+               final int style;
+               final String custom;
+               if (lead == partProviders) {
+                       style = SWT.LEAD;
+                       custom = CmsStyles.CMS_HEADER_LEAD;
+               } else if (center == partProviders) {
+                       style = SWT.CENTER;
+                       custom = CmsStyles.CMS_HEADER_CENTER;
+               } else if (end == partProviders) {
+                       style = SWT.END;
+                       custom = CmsStyles.CMS_HEADER_END;
+               } else {
+                       throw new CmsException("Unsupported part providers " + partProviders);
+               }
+
+               Composite part = new Composite(parent, SWT.NONE);
+               part.setData(RWT.CUSTOM_VARIANT, custom);
+               GridData gridData = new GridData(style, SWT.FILL, true, true);
+               part.setLayoutData(gridData);
+               part.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(partProviders.size(), subPartsSameWidth)));
+               for (CmsUiProvider uiProvider : partProviders) {
+                       Control subPart = uiProvider.createUi(part, context);
+                       subPart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+               }
+       }
+
+       public void setLead(List<CmsUiProvider> lead) {
+               this.lead = lead;
+       }
+
+       public void setCenter(List<CmsUiProvider> center) {
+               this.center = center;
+       }
+
+       public void setEnd(List<CmsUiProvider> end) {
+               this.end = end;
+       }
+
+       public void setSubPartsSameWidth(Boolean subPartsSameWidth) {
+               this.subPartsSameWidth = subPartsSameWidth;
+       }
+
+       public List<CmsUiProvider> getLead() {
+               return lead;
+       }
+
+       public List<CmsUiProvider> getCenter() {
+               return center;
+       }
+
+       public List<CmsUiProvider> getEnd() {
+               return end;
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SimpleDynamicPages.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SimpleDynamicPages.java
new file mode 100644 (file)
index 0000000..c61a2fc
--- /dev/null
@@ -0,0 +1,118 @@
+package org.argeo.cms.ui.util;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+public class SimpleDynamicPages implements CmsUiProvider {
+
+       @Override
+       public Control createUi(Composite parent, Node context)
+                       throws RepositoryException {
+               if (context == null)
+                       throw new CmsException("Context cannot be null");
+               parent.setLayout(new GridLayout(2, false));
+
+               // parent
+               if (!context.getPath().equals("/")) {
+                       new CmsLink("..", context.getParent().getPath()).createUi(parent,
+                                       context);
+                       new Label(parent, SWT.NONE).setText(context.getParent()
+                                       .getPrimaryNodeType().getName());
+               }
+
+               // context
+               Label contextL = new Label(parent, SWT.NONE);
+               contextL.setData(RWT.MARKUP_ENABLED, true);
+               contextL.setText("<b>" + context.getName() + "</b>");
+               new Label(parent, SWT.NONE).setText(context.getPrimaryNodeType()
+                               .getName());
+
+               // children
+               // Label childrenL = new Label(parent, SWT.NONE);
+               // childrenL.setData(RWT.MARKUP_ENABLED, true);
+               // childrenL.setText("<i>Children:</i>");
+               // childrenL.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false,
+               // false, 2, 1));
+
+               for (NodeIterator nIt = context.getNodes(); nIt.hasNext();) {
+                       Node child = nIt.nextNode();
+                       new CmsLink(child.getName(), child.getPath()).createUi(parent,
+                                       context);
+
+                       new Label(parent, SWT.NONE).setText(child.getPrimaryNodeType()
+                                       .getName());
+               }
+
+               // properties
+               // Label propsL = new Label(parent, SWT.NONE);
+               // propsL.setData(RWT.MARKUP_ENABLED, true);
+               // propsL.setText("<i>Properties:</i>");
+               // propsL.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false,
+               // 2, 1));
+               for (PropertyIterator pIt = context.getProperties(); pIt.hasNext();) {
+                       Property property = pIt.nextProperty();
+
+                       Label label = new Label(parent, SWT.NONE);
+                       label.setText(property.getName());
+                       label.setToolTipText(JcrUtils
+                                       .getPropertyDefinitionAsString(property));
+
+                       new Label(parent, SWT.NONE).setText(getPropAsString(property));
+               }
+
+               return null;
+       }
+
+       private String getPropAsString(Property property)
+                       throws RepositoryException {
+               String result = "";
+               DateFormat timeFormatter = new SimpleDateFormat("");
+               if (property.isMultiple()) {
+                       result = getMultiAsString(property, ", ");
+               } else {
+                       Value value = property.getValue();
+                       if (value.getType() == PropertyType.BINARY)
+                               result = "<binary>";
+                       else if (value.getType() == PropertyType.DATE)
+                               result = timeFormatter.format(value.getDate().getTime());
+                       else
+                               result = value.getString();
+               }
+               return result;
+       }
+
+       private String getMultiAsString(Property property, String separator)
+                       throws RepositoryException {
+               if (separator == null)
+                       separator = "; ";
+               Value[] values = property.getValues();
+               StringBuilder builder = new StringBuilder();
+               for (Value val : values) {
+                       String currStr = val.getString();
+                       if (!"".equals(currStr.trim()))
+                               builder.append(currStr).append(separator);
+               }
+               if (builder.lastIndexOf(separator) >= 0)
+                       return builder.substring(0, builder.length() - separator.length());
+               else
+                       return builder.toString();
+       }
+}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SimpleStaticPage.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SimpleStaticPage.java
new file mode 100644 (file)
index 0000000..63e504b
--- /dev/null
@@ -0,0 +1,32 @@
+package org.argeo.cms.ui.util;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.CmsStyles;
+import org.argeo.cms.ui.CmsUiProvider;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+public class SimpleStaticPage implements CmsUiProvider {
+       private String text;
+
+       @Override
+       public Control createUi(Composite parent, Node context)
+                       throws RepositoryException {
+               Label textC = new Label(parent,  SWT.WRAP);
+               textC.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_STATIC_TEXT);
+               textC.setData(RWT.MARKUP_ENABLED, Boolean.TRUE);
+               textC.setText(text);
+               
+               return textC;
+       }
+
+       public void setText(String text) {
+               this.text = text;
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SimpleStyle.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SimpleStyle.java
new file mode 100644 (file)
index 0000000..b5fca26
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.cms.ui.util;
+
+import org.argeo.api.cms.ux.CmsStyle;
+
+/** Simple styles used by the CMS UI utilities. */
+public enum SimpleStyle implements CmsStyle {
+       link;
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/StyleSheetResourceLoader.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/StyleSheetResourceLoader.java
new file mode 100644 (file)
index 0000000..1e17dc9
--- /dev/null
@@ -0,0 +1,71 @@
+package org.argeo.cms.ui.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.cms.swt.CmsException;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.osgi.framework.Bundle;
+
+/** {@link ResourceLoader} caching stylesheets. */
+public class StyleSheetResourceLoader implements ResourceLoader {
+       private Bundle themeBundle;
+       private Map<String, StyleSheet> stylesheets = new LinkedHashMap<String, StyleSheet>();
+
+       public StyleSheetResourceLoader(Bundle themeBundle) {
+               this.themeBundle = themeBundle;
+       }
+
+       @Override
+       public InputStream getResourceAsStream(String resourceName) throws IOException {
+               if (!stylesheets.containsKey(resourceName)) {
+                       // TODO deal with other bundles
+                       // Bundle bundle = bundleContext.getBundle();
+                       // String location =
+                       // bundle.getLocation().substring("initial@reference:".length());
+                       // if (location.startsWith("file:")) {
+                       // Path path = null;
+                       // try {
+                       // path = Paths.get(new URI(location));
+                       // } catch (URISyntaxException e) {
+                       // e.printStackTrace();
+                       // }
+                       // if (path != null) {
+                       // Path resourcePath = path.resolve(resourceName);
+                       // if (Files.exists(resourcePath))
+                       // return Files.newInputStream(resourcePath);
+                       // }
+                       // }
+
+                       URL res = themeBundle.getEntry(resourceName);
+                       if (res == null)
+                               throw new CmsException(
+                                               "Entry " + resourceName + " not found in bundle " + themeBundle.getSymbolicName());
+                       ByteArrayOutputStream out = new ByteArrayOutputStream();
+                       IOUtils.copy(res.openStream(), out);
+                       stylesheets.put(resourceName, new StyleSheet(out.toByteArray()));
+               }
+               return new ByteArrayInputStream(stylesheets.get(resourceName).getData());
+               // return res.openStream();
+       }
+
+       private class StyleSheet {
+               private byte[] data;
+
+               public StyleSheet(byte[] data) {
+                       super();
+                       this.data = data;
+               }
+
+               public byte[] getData() {
+                       return data;
+               }
+
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SystemNotifications.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/SystemNotifications.java
new file mode 100644 (file)
index 0000000..5a00781
--- /dev/null
@@ -0,0 +1,129 @@
+package org.argeo.cms.ui.util;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.swt.CmsStyles;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/** Shell displaying system notifications such as exceptions */
+public class SystemNotifications extends Shell implements CmsStyles,
+               MouseListener {
+       private static final long serialVersionUID = -8129377525216022683L;
+
+       private Control source;
+
+       public SystemNotifications(Control source) {
+               super(source.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+               setData(RWT.CUSTOM_VARIANT, CMS_USER_MENU);
+
+               this.source = source;
+
+               // TODO UI
+               // setLocation(source.toDisplay(source.getSize().x - getSize().x,
+               // source.getSize().y));
+               setLayout(new GridLayout());
+               addMouseListener(this);
+
+               addShellListener(new ShellAdapter() {
+                       private static final long serialVersionUID = 5178980294808435833L;
+
+                       @Override
+                       public void shellDeactivated(ShellEvent e) {
+                               close();
+                               dispose();
+                       }
+               });
+
+       }
+
+       public void notifyException(Throwable exception) {
+               Composite pane = this;
+
+               Label lbl = new Label(pane, SWT.NONE);
+               lbl.setText(exception.getLocalizedMessage()
+                               + (exception instanceof CmsException ? "" : "("
+                                               + exception.getClass().getName() + ")") + "\n");
+               lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+               lbl.addMouseListener(this);
+               if (exception.getCause() != null)
+                       appendCause(pane, exception.getCause());
+
+               StringBuilder mailToUrl = new StringBuilder("mailto:?");
+               try {
+                       mailToUrl.append("subject=").append(
+                                       URLEncoder.encode(
+                                                       "Exception "
+                                                                       + new SimpleDateFormat("yyyy-MM-dd hh:mm")
+                                                                                       .format(new Date()), "UTF-8")
+                                                       .replace("+", "%20"));
+
+                       StringWriter sw = new StringWriter();
+                       exception.printStackTrace(new PrintWriter(sw));
+                       IOUtils.closeQuietly(sw);
+
+                       // see
+                       // http://stackoverflow.com/questions/4737841/urlencoder-not-able-to-translate-space-character
+                       String encoded = URLEncoder.encode(sw.toString(), "UTF-8").replace(
+                                       "+", "%20");
+                       mailToUrl.append("&amp;body=").append(encoded);
+               } catch (UnsupportedEncodingException e) {
+                       mailToUrl.append("&amp;body=").append("Could not encode: ")
+                                       .append(e.getMessage());
+               }
+               Label mailTo = new Label(pane, SWT.NONE);
+               CmsSwtUtils.markup(mailTo);
+               mailTo.setText("<a href=\"" + mailToUrl + "\">Send details</a>");
+               mailTo.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
+
+               pack();
+               layout();
+
+               setLocation(source.toDisplay(source.getSize().x - getSize().x,
+                               source.getSize().y - getSize().y));
+               open();
+       }
+
+       private void appendCause(Composite parent, Throwable e) {
+               Label lbl = new Label(parent, SWT.NONE);
+               lbl.setText(" caused by: " + e.getLocalizedMessage() + " ("
+                               + e.getClass().getName() + ")" + "\n");
+               lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+               lbl.addMouseListener(this);
+               if (e.getCause() != null)
+                       appendCause(parent, e.getCause());
+       }
+
+       @Override
+       public void mouseDoubleClick(MouseEvent e) {
+       }
+
+       @Override
+       public void mouseDown(MouseEvent e) {
+               close();
+               dispose();
+       }
+
+       @Override
+       public void mouseUp(MouseEvent e) {
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/UserMenu.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/UserMenu.java
new file mode 100644 (file)
index 0000000..09aeff6
--- /dev/null
@@ -0,0 +1,56 @@
+package org.argeo.cms.ui.util;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.swt.CmsException;
+import org.argeo.cms.swt.auth.CmsLoginShell;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/** The site-related user menu */
+public class UserMenu extends CmsLoginShell {
+       private final Control source;
+       private final Node context;
+
+       public UserMenu(Control source, Node context) {
+               // FIXME pass CMS context
+               super(CmsUiUtils.getCmsView(), null);
+               this.context = context;
+               createUi();
+               if (source == null)
+                       throw new CmsException("Source control cannot be null.");
+               this.source = source;
+               open();
+       }
+
+       @Override
+       protected Shell createShell() {
+               return new Shell(Display.getCurrent(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
+       }
+
+       @Override
+       public void open() {
+               Shell shell = getShell();
+               shell.pack();
+               shell.layout();
+               shell.setLocation(source.toDisplay(source.getSize().x - shell.getSize().x, source.getSize().y));
+               shell.addShellListener(new ShellAdapter() {
+                       private static final long serialVersionUID = 5178980294808435833L;
+
+                       @Override
+                       public void shellDeactivated(ShellEvent e) {
+                               closeShell();
+                       }
+               });
+               super.open();
+       }
+
+       protected Node getContext() {
+               return context;
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/UserMenuLink.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/UserMenuLink.java
new file mode 100644 (file)
index 0000000..317a7b5
--- /dev/null
@@ -0,0 +1,84 @@
+package org.argeo.cms.ui.util;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.CmsMsg;
+import org.argeo.cms.auth.CurrentUser;
+import org.argeo.cms.swt.CmsStyles;
+import org.argeo.cms.swt.auth.CmsLoginShell;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+/** Open the user menu when clicked */
+public class UserMenuLink extends MenuLink {
+
+       public UserMenuLink() {
+               setCustom(CmsStyles.CMS_USER_MENU_LINK);
+       }
+
+       @Override
+       public Control createUi(Composite parent, Node context) {
+               if (CurrentUser.isAnonymous())
+                       setLabel(CmsMsg.login.lead());
+               else {
+                       setLabel(CurrentUser.getDisplayName());
+               }
+               Label link = (Label) ((Composite) super.createUi(parent, context)).getChildren()[0];
+               link.addMouseListener(new UserMenuLinkController(context));
+               return link.getParent();
+       }
+
+       protected CmsLoginShell createUserMenu(Control source, Node context) {
+               return new UserMenu(source.getParent(), context);
+       }
+
+       private class UserMenuLinkController implements MouseListener, DisposeListener {
+               private static final long serialVersionUID = 3634864186295639792L;
+
+               private CmsLoginShell userMenu = null;
+               private long lastDisposeTS = 0l;
+
+               private final Node context;
+
+               public UserMenuLinkController(Node context) {
+                       this.context = context;
+               }
+
+               //
+               // MOUSE LISTENER
+               //
+               @Override
+               public void mouseDown(MouseEvent e) {
+                       if (e.button == 1) {
+                               Control source = (Control) e.getSource();
+                               if (userMenu == null) {
+                                       long durationSinceLastDispose = System.currentTimeMillis() - lastDisposeTS;
+                                       // avoid to reopen the menu, if one has clicked gain
+                                       if (durationSinceLastDispose > 200) {
+                                               userMenu = createUserMenu(source, context);
+                                               userMenu.getShell().addDisposeListener(this);
+                                       }
+                               }
+                       }
+               }
+
+               @Override
+               public void mouseDoubleClick(MouseEvent e) {
+               }
+
+               @Override
+               public void mouseUp(MouseEvent e) {
+               }
+
+               @Override
+               public void widgetDisposed(DisposeEvent event) {
+                       userMenu = null;
+                       lastDisposeTS = System.currentTimeMillis();
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/VerticalMenu.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/VerticalMenu.java
new file mode 100644 (file)
index 0000000..7f846c9
--- /dev/null
@@ -0,0 +1,44 @@
+package org.argeo.cms.ui.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.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;
+
+public class VerticalMenu implements CmsUiProvider {
+       private List<CmsUiProvider> items = new ArrayList<CmsUiProvider>();
+
+       @Override
+       public Control createUi(Composite parent, Node context) throws RepositoryException {
+               Composite part = new Composite(parent, SWT.NONE);
+               part.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
+//             part.setData(RWT.CUSTOM_VARIANT, custom);
+               part.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               for (CmsUiProvider uiProvider : items) {
+                       Control subPart = uiProvider.createUi(part, context);
+                       subPart.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
+               }
+               return part;
+       }
+
+       public void add(CmsUiProvider uiProvider) {
+               items.add(uiProvider);
+       }
+
+       public List<CmsUiProvider> getItems() {
+               return items;
+       }
+
+       public void setItems(List<CmsUiProvider> items) {
+               this.items = items;
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/package-info.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/util/package-info.java
new file mode 100644 (file)
index 0000000..566df88
--- /dev/null
@@ -0,0 +1,2 @@
+/** Argeo CMS UI utilities. */
+package org.argeo.cms.ui.util;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/AbstractPageViewer.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/AbstractPageViewer.java
new file mode 100644 (file)
index 0000000..e23846e
--- /dev/null
@@ -0,0 +1,351 @@
+package org.argeo.cms.ui.viewers;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.security.auth.Subject;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.CmsEditable;
+import org.argeo.cms.swt.SwtEditablePart;
+import org.argeo.cms.swt.widgets.ScrolledPage;
+import org.argeo.jcr.JcrException;
+import org.eclipse.jface.viewers.ContentViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Widget;
+import org.xml.sax.SAXParseException;
+
+/** Base class for viewers related to a page */
+public abstract class AbstractPageViewer extends ContentViewer implements Observer {
+       private static final long serialVersionUID = 5438688173410341485L;
+
+       private final static CmsLog log = CmsLog.getLog(AbstractPageViewer.class);
+
+       private final boolean readOnly;
+       /** The basis for the layouts, typically a ScrolledPage. */
+       private final Composite page;
+       private final CmsEditable cmsEditable;
+
+       private MouseListener mouseListener;
+       private FocusListener focusListener;
+
+       private SwtEditablePart edited;
+       private ISelection selection = StructuredSelection.EMPTY;
+
+       private AccessControlContext accessControlContext;
+
+       protected AbstractPageViewer(Section parent, int style, CmsEditable cmsEditable) {
+               // read only at UI level
+               readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
+
+               this.cmsEditable = cmsEditable == null ? CmsEditable.NON_EDITABLE : cmsEditable;
+               if (this.cmsEditable instanceof Observable)
+                       ((Observable) this.cmsEditable).addObserver(this);
+
+               if (cmsEditable.canEdit()) {
+                       mouseListener = createMouseListener();
+                       focusListener = createFocusListener();
+               }
+               page = findPage(parent);
+               accessControlContext = AccessController.getContext();
+       }
+
+       /**
+        * Can be called to simplify the called to isModelInitialized() and initModel()
+        */
+       protected void initModelIfNeeded(Node node) {
+               try {
+                       if (!isModelInitialized(node))
+                               if (getCmsEditable().canEdit()) {
+                                       initModel(node);
+                                       node.getSession().save();
+                               }
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot initialize model", e);
+               }
+       }
+
+       /** Called if user can edit and model is not initialized */
+       protected Boolean isModelInitialized(Node node) throws RepositoryException {
+               return true;
+       }
+
+       /** Called if user can edit and model is not initialized */
+       protected void initModel(Node node) throws RepositoryException {
+       }
+
+       /** Create (retrieve) the MouseListener to use. */
+       protected MouseListener createMouseListener() {
+               return new MouseAdapter() {
+                       private static final long serialVersionUID = 1L;
+               };
+       }
+
+       /** Create (retrieve) the FocusListener to use. */
+       protected FocusListener createFocusListener() {
+               return new FocusListener() {
+                       private static final long serialVersionUID = 1L;
+
+                       @Override
+                       public void focusLost(FocusEvent event) {
+                       }
+
+                       @Override
+                       public void focusGained(FocusEvent event) {
+                       }
+               };
+       }
+
+       protected Composite findPage(Composite composite) {
+               if (composite instanceof ScrolledPage) {
+                       return (ScrolledPage) composite;
+               } else {
+                       if (composite.getParent() == null)
+                               return composite;
+                       return findPage(composite.getParent());
+               }
+       }
+
+       public void layoutPage() {
+               if (page != null)
+                       page.layout(true, true);
+       }
+
+       protected void showControl(Control control) {
+               if (page != null && (page instanceof ScrolledPage))
+                       ((ScrolledPage) page).showControl(control);
+       }
+
+       @Override
+       public void update(Observable o, Object arg) {
+               if (o == cmsEditable)
+                       editingStateChanged(cmsEditable);
+       }
+
+       /** To be overridden in order to provide the actual refresh */
+       protected void refresh(Control control) throws RepositoryException {
+       }
+
+       /** To be overridden.Save the edited part. */
+       protected void save(SwtEditablePart part) throws RepositoryException {
+       }
+
+       /** Prepare the edited part */
+       protected void prepare(SwtEditablePart part, Object caretPosition) {
+       }
+
+       /** Notified when the editing state changed. Does nothing, to be overridden */
+       protected void editingStateChanged(CmsEditable cmsEditable) {
+       }
+
+       @Override
+       public void refresh() {
+               // TODO check actual context in order to notice a discrepancy
+               Subject viewerSubject = getViewerSubject();
+               Subject.doAs(viewerSubject, (PrivilegedAction<Void>) () -> {
+                       try {
+                               if (cmsEditable.canEdit() && !readOnly)
+                                       mouseListener = createMouseListener();
+                               else
+                                       mouseListener = null;
+                               refresh(getControl());
+                               // layout(getControl());
+                               if (!getControl().isDisposed())
+                                       layoutPage();
+                       } catch (RepositoryException e) {
+                               throw new JcrException("Cannot refresh", e);
+                       }
+                       return null;
+               });
+       }
+
+       @Override
+       public void setSelection(ISelection selection, boolean reveal) {
+               this.selection = selection;
+       }
+
+       protected void updateContent(SwtEditablePart part) throws RepositoryException {
+       }
+
+       // LOW LEVEL EDITION
+       protected void edit(SwtEditablePart part, Object caretPosition) {
+               try {
+                       if (edited == part)
+                               return;
+
+                       if (edited != null && edited != part) {
+                               SwtEditablePart previouslyEdited = edited;
+                               try {
+                                       stopEditing(true);
+                               } catch (Exception e) {
+                                       notifyEditionException(e);
+                                       edit(previouslyEdited, caretPosition);
+                                       return;
+                               }
+                       }
+
+                       part.startEditing();
+                       edited = part;
+                       updateContent(part);
+                       prepare(part, caretPosition);
+                       edited.getControl().addFocusListener(new FocusListener() {
+                               private static final long serialVersionUID = 6883521812717097017L;
+
+                               @Override
+                               public void focusLost(FocusEvent event) {
+                                       stopEditing(true);
+                               }
+
+                               @Override
+                               public void focusGained(FocusEvent event) {
+                               }
+                       });
+
+                       layout(part.getControl());
+                       showControl(part.getControl());
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot edit " + part, e);
+               }
+       }
+
+       protected void stopEditing(Boolean save) {
+               if (edited instanceof Widget && ((Widget) edited).isDisposed()) {
+                       edited = null;
+                       return;
+               }
+
+               assert edited != null;
+               if (edited == null) {
+                       if (log.isTraceEnabled())
+                               log.warn("Told to stop editing while not editing anything");
+                       return;
+               }
+
+               try {
+                       if (save)
+                               save(edited);
+
+                       edited.stopEditing();
+                       SwtEditablePart editablePart = edited;
+                       Control control = ((SwtEditablePart) edited).getControl();
+                       edited = null;
+                       // TODO make edited state management more robust
+                       updateContent(editablePart);
+                       layout(control);
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot stop editing", e);
+               } finally {
+                       edited = null;
+               }
+       }
+
+       // METHODS AVAILABLE TO EXTENDING CLASSES
+       protected void saveEdit() {
+               if (edited != null)
+                       stopEditing(true);
+       }
+
+       protected void cancelEdit() {
+               if (edited != null)
+                       stopEditing(false);
+       }
+
+       /** Layout this controls from the related base page. */
+       public void layout(Control... controls) {
+               page.layout(controls);
+       }
+
+       /**
+        * Find the first {@link SwtEditablePart} in the parents hierarchy of this control
+        */
+       protected SwtEditablePart findDataParent(Control parent) {
+               if (parent instanceof SwtEditablePart) {
+                       return (SwtEditablePart) parent;
+               }
+               if (parent.getParent() != null)
+                       return findDataParent(parent.getParent());
+               else
+                       throw new IllegalStateException("No data parent found");
+       }
+
+       // UTILITIES
+       /** Check whether the edited part is in a proper state */
+       protected void checkEdited() {
+               if (edited == null || (edited instanceof Widget) && ((Widget) edited).isDisposed())
+                       throw new IllegalStateException("Edited should not be null or disposed at this stage");
+       }
+
+       /** Persist all changes. */
+       protected void persistChanges(Session session) throws RepositoryException {
+               session.save();
+               session.refresh(false);
+               // TODO notify that changes have been persisted
+       }
+
+       /** Convenience method using a Node in order to save the underlying session. */
+       protected void persistChanges(Node anyNode) throws RepositoryException {
+               persistChanges(anyNode.getSession());
+       }
+
+       /** Notify edition exception */
+       protected void notifyEditionException(Throwable e) {
+               Throwable eToLog = e;
+               if (e instanceof IllegalArgumentException)
+                       if (e.getCause() instanceof SAXParseException)
+                               eToLog = e.getCause();
+               log.error(eToLog.getMessage(), eToLog);
+//             if (log.isTraceEnabled())
+//                     log.trace("Full stack of " + eToLog.getMessage(), e);
+               // TODO Light error notification popup
+       }
+
+       protected Subject getViewerSubject() {
+               Subject res = null;
+               if (accessControlContext != null) {
+                       res = Subject.getSubject(accessControlContext);
+               }
+               if (res == null)
+                       throw new IllegalStateException("No subject associated with this viewer");
+               return res;
+       }
+
+       // GETTERS / SETTERS
+       public boolean isReadOnly() {
+               return readOnly;
+       }
+
+       protected SwtEditablePart getEdited() {
+               return edited;
+       }
+
+       public MouseListener getMouseListener() {
+               return mouseListener;
+       }
+
+       public FocusListener getFocusListener() {
+               return focusListener;
+       }
+
+       public CmsEditable getCmsEditable() {
+               return cmsEditable;
+       }
+
+       @Override
+       public ISelection getSelection() {
+               return selection;
+       }
+}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/ItemPart.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/ItemPart.java
new file mode 100644 (file)
index 0000000..4ca45d1
--- /dev/null
@@ -0,0 +1,9 @@
+package org.argeo.cms.ui.viewers;
+
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+
+/** An editable part related to a JCR Item */
+public interface ItemPart<T extends Item> {
+       public Item getItem() throws RepositoryException;
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/JcrVersionCmsEditable.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/JcrVersionCmsEditable.java
new file mode 100644 (file)
index 0000000..298fbde
--- /dev/null
@@ -0,0 +1,94 @@
+package org.argeo.cms.ui.viewers;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.version.VersionManager;
+
+import org.argeo.api.cms.ux.CmsEditionEvent;
+import org.argeo.cms.ux.AbstractCmsEditable;
+import org.argeo.jcr.JcrException;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+/** Provides the CmsEditable semantic based on JCR versioning. */
+public class JcrVersionCmsEditable extends AbstractCmsEditable {
+       private final String nodePath;// cache
+       private final VersionManager versionManager;
+       private final Boolean canEdit;
+
+       public JcrVersionCmsEditable(Node node) throws RepositoryException {
+               this.nodePath = node.getPath();
+               if (node.getSession().hasPermission(node.getPath(), Session.ACTION_SET_PROPERTY)) {
+                       // was Session.ACTION_ADD_NODE
+                       canEdit = true;
+                       if (!node.isNodeType(NodeType.MIX_VERSIONABLE)) {
+                               node.addMixin(NodeType.MIX_VERSIONABLE);
+                               node.getSession().save();
+                       }
+                       versionManager = node.getSession().getWorkspace().getVersionManager();
+               } else {
+                       canEdit = false;
+                       versionManager = null;
+               }
+
+               // bind keys
+               if (canEdit) {
+                       Display display = Display.getCurrent();
+                       display.setData(RWT.ACTIVE_KEYS, new String[] { "CTRL+RETURN", "CTRL+E" });
+                       display.addFilter(SWT.KeyDown, new Listener() {
+                               private static final long serialVersionUID = -4378653870463187318L;
+
+                               public void handleEvent(Event e) {
+                                       boolean ctrlPressed = (e.stateMask & SWT.CTRL) != 0;
+                                       if (ctrlPressed && e.keyCode == '\r')
+                                               stopEditing();
+                                       else if (ctrlPressed && e.keyCode == 'E')
+                                               stopEditing();
+                               }
+                       });
+               }
+       }
+
+       @Override
+       public Boolean canEdit() {
+               return canEdit;
+       }
+
+       public Boolean isEditing() {
+               try {
+                       if (!canEdit())
+                               return false;
+                       return versionManager.isCheckedOut(nodePath);
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot check whether " + nodePath + " is editing", e);
+               }
+       }
+
+       @Override
+       public void startEditing() {
+               try {
+                       versionManager.checkout(nodePath);
+//                     setChanged();
+               } catch (RepositoryException e1) {
+                       throw new JcrException("Cannot publish " + nodePath, e1);
+               }
+               notifyListeners(new CmsEditionEvent(nodePath, CmsEditionEvent.START_EDITING, this));
+       }
+
+       @Override
+       public void stopEditing() {
+               try {
+                       versionManager.checkin(nodePath);
+//                     setChanged();
+               } catch (RepositoryException e1) {
+                       throw new JcrException("Cannot publish " + nodePath, e1);
+               }
+               notifyListeners(new CmsEditionEvent(nodePath, CmsEditionEvent.STOP_EDITING, this));
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/NodePart.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/NodePart.java
new file mode 100644 (file)
index 0000000..b51d4fc
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.cms.ui.viewers;
+
+import javax.jcr.Node;
+
+/** An editable part related to a node */
+public interface NodePart extends ItemPart<Node> {
+       public Node getNode();
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/PropertyPart.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/PropertyPart.java
new file mode 100644 (file)
index 0000000..793079e
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.cms.ui.viewers;
+
+import javax.jcr.Property;
+
+/** An editable part related to a JCR Property */
+public interface PropertyPart extends ItemPart<Property> {
+       public Property getProperty();
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/Section.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/Section.java
new file mode 100644 (file)
index 0000000..b27fa38
--- /dev/null
@@ -0,0 +1,166 @@
+package org.argeo.cms.ui.viewers;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.SwtEditablePart;
+import org.argeo.cms.ui.widgets.JcrComposite;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** A structured UI related to a JCR context. */
+public class Section extends JcrComposite {
+       private static final long serialVersionUID = -5933796173755739207L;
+
+       private final Section parentSection;
+       private Composite sectionHeader;
+       private final Integer relativeDepth;
+
+       public Section(Composite parent, int style, Node node) {
+               this(parent, findSection(parent), style, node);
+       }
+
+       public Section(Section section, int style, Node node) {
+               this(section, section, style, node);
+       }
+
+       protected Section(Composite parent, Section parentSection, int style, Node node) {
+               super(parent, style, node);
+               try {
+                       this.parentSection = parentSection;
+                       if (parentSection != null) {
+                               relativeDepth = getNode().getDepth() - parentSection.getNode().getDepth();
+                       } else {
+                               relativeDepth = 0;
+                       }
+                       setLayout(CmsSwtUtils.noSpaceGridLayout());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot create section from " + node, e);
+               }
+       }
+
+       public Map<String, Section> getSubSections() throws RepositoryException {
+               LinkedHashMap<String, Section> result = new LinkedHashMap<String, Section>();
+               for (Control child : getChildren()) {
+                       if (child instanceof Composite) {
+                               collectDirectSubSections((Composite) child, result);
+                       }
+               }
+               return Collections.unmodifiableMap(result);
+       }
+
+       private void collectDirectSubSections(Composite composite, LinkedHashMap<String, Section> subSections)
+                       throws RepositoryException {
+               if (composite == sectionHeader || composite instanceof SwtEditablePart)
+                       return;
+               if (composite instanceof Section) {
+                       Section section = (Section) composite;
+                       subSections.put(section.getNodeId(), section);
+                       return;
+               }
+
+               for (Control child : composite.getChildren())
+                       if (child instanceof Composite)
+                               collectDirectSubSections((Composite) child, subSections);
+       }
+
+       public Composite createHeader() {
+               return createHeader(this);
+       }
+
+       public Composite createHeader(Composite parent) {
+               if (sectionHeader != null)
+                       sectionHeader.dispose();
+
+               sectionHeader = new Composite(parent, SWT.NONE);
+               sectionHeader.setLayoutData(CmsSwtUtils.fillWidth());
+               sectionHeader.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               // sectionHeader.moveAbove(null);
+               // layout();
+               return sectionHeader;
+       }
+
+       public Composite getHeader() {
+               if (sectionHeader != null && sectionHeader.isDisposed())
+                       sectionHeader = null;
+               return sectionHeader;
+       }
+
+       // SECTION PARTS
+       public SectionPart getSectionPart(String partId) {
+               for (Control child : getChildren()) {
+                       if (child instanceof SectionPart) {
+                               SectionPart sectionPart = (SectionPart) child;
+                               if (sectionPart.getPartId().equals(partId))
+                                       return sectionPart;
+                       }
+               }
+               return null;
+       }
+
+       public SectionPart nextSectionPart(SectionPart sectionPart) {
+               Control[] children = getChildren();
+               for (int i = 0; i < children.length; i++) {
+                       if (sectionPart == children[i]) {
+                               for (int j = i + 1; j < children.length; j++) {
+                                       if (children[i + 1] instanceof SectionPart) {
+                                               return (SectionPart) children[i + 1];
+                                       }
+                               }
+
+//                             if (i + 1 < children.length) {
+//                                     Composite next = (Composite) children[i + 1];
+//                                     return (SectionPart) next;
+//                             } else {
+//                                     // next section
+//                             }
+                       }
+               }
+               return null;
+       }
+
+       public SectionPart previousSectionPart(SectionPart sectionPart) {
+               Control[] children = getChildren();
+               for (int i = 0; i < children.length; i++) {
+                       if (sectionPart == children[i])
+                               if (i != 0) {
+                                       Composite previous = (Composite) children[i - 1];
+                                       return (SectionPart) previous;
+                               } else {
+                                       // previous section
+                               }
+               }
+               return null;
+       }
+
+       @Override
+       public String toString() {
+               if (parentSection == null)
+                       return "Main section " + getNode();
+               return "Section " + getNode();
+       }
+
+       public Section getParentSection() {
+               return parentSection;
+       }
+
+       public Integer getRelativeDepth() {
+               return relativeDepth;
+       }
+
+       /** Recursively finds the related section in the parents (can be itself) */
+       public static Section findSection(Control control) {
+               if (control == null)
+                       return null;
+               if (control instanceof Section)
+                       return (Section) control;
+               else
+                       return findSection(control.getParent());
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/SectionPart.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/SectionPart.java
new file mode 100644 (file)
index 0000000..4278c83
--- /dev/null
@@ -0,0 +1,10 @@
+package org.argeo.cms.ui.viewers;
+
+import org.argeo.cms.swt.SwtEditablePart;
+
+/** An editable part dynamically related to a Section */
+public interface SectionPart extends SwtEditablePart, NodePart {
+       public String getPartId();
+
+       public Section getSection();
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/package-info.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/viewers/package-info.java
new file mode 100644 (file)
index 0000000..2f07931
--- /dev/null
@@ -0,0 +1,2 @@
+/** Argeo CMS generic viewers, based on JFace. */
+package org.argeo.cms.ui.viewers;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/EditableImage.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/EditableImage.java
new file mode 100644 (file)
index 0000000..95d9e8e
--- /dev/null
@@ -0,0 +1,112 @@
+package org.argeo.cms.ui.widgets;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** A stylable and editable image. */
+public abstract class EditableImage extends StyledControl {
+       private static final long serialVersionUID = -5689145523114022890L;
+       private final static CmsLog log = CmsLog.getLog(EditableImage.class);
+
+       private Cms2DSize preferredImageSize;
+       private Boolean loaded = false;
+
+       public EditableImage(Composite parent, int swtStyle) {
+               super(parent, swtStyle);
+       }
+
+       public EditableImage(Composite parent, int swtStyle, Cms2DSize preferredImageSize) {
+               super(parent, swtStyle);
+               this.preferredImageSize = preferredImageSize;
+       }
+
+       public EditableImage(Composite parent, int style, Node node, boolean cacheImmediately, Cms2DSize preferredImageSize)
+                       throws RepositoryException {
+               super(parent, style, node, cacheImmediately);
+               this.preferredImageSize = preferredImageSize;
+       }
+
+       @Override
+       protected void setContainerLayoutData(Composite composite) {
+               // composite.setLayoutData(fillWidth());
+       }
+
+       @Override
+       protected void setControlLayoutData(Control control) {
+               // control.setLayoutData(fillWidth());
+       }
+
+       /** To be overriden. */
+       protected String createImgTag() throws RepositoryException {
+               return CmsUiUtils
+                               .noImg(preferredImageSize != null ? preferredImageSize : new Cms2DSize(getSize().x, getSize().y));
+       }
+
+       protected Label createLabel(Composite box, String style) {
+               Label lbl = new Label(box, getStyle());
+               // lbl.setLayoutData(CmsUiUtils.fillWidth());
+               CmsSwtUtils.markup(lbl);
+               CmsSwtUtils.style(lbl, style);
+               if (mouseListener != null)
+                       lbl.addMouseListener(mouseListener);
+               load(lbl);
+               return lbl;
+       }
+
+       /** To be overriden. */
+       protected synchronized Boolean load(Control control) {
+               String imgTag;
+               try {
+                       imgTag = createImgTag();
+               } catch (Exception e) {
+                       // throw new CmsException("Cannot retrieve image", e);
+                       log.error("Cannot retrieve image", e);
+                       imgTag = CmsUiUtils.noImg(preferredImageSize);
+                       loaded = false;
+               }
+
+               if (imgTag == null) {
+                       loaded = false;
+                       imgTag = CmsUiUtils.noImg(preferredImageSize);
+               } else
+                       loaded = true;
+               if (control != null) {
+                       ((Label) control).setText(imgTag);
+                       control.setSize(preferredImageSize != null
+                                       ? new Point(preferredImageSize.getWidth(), preferredImageSize.getHeight())
+                                       : getSize());
+               } else {
+                       loaded = false;
+               }
+               getParent().layout();
+               return loaded;
+       }
+
+       public void setPreferredSize(Cms2DSize size) {
+               this.preferredImageSize = size;
+               if (!loaded) {
+                       load((Label) getControl());
+               }
+       }
+
+       protected Text createText(Composite box, String style) {
+               Text text = new Text(box, getStyle());
+               CmsSwtUtils.style(text, style);
+               return text;
+       }
+
+       public Cms2DSize getPreferredImageSize() {
+               return preferredImageSize;
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/EditableText.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/EditableText.java
new file mode 100644 (file)
index 0000000..e3499ac
--- /dev/null
@@ -0,0 +1,145 @@
+package org.argeo.cms.ui.widgets;
+
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Editable text part displaying styled text. */
+public class EditableText extends StyledControl {
+       private static final long serialVersionUID = -6372283442330912755L;
+
+       private boolean editable = true;
+
+       private Color highlightColor;
+       private Composite highlight;
+
+       private boolean useTextAsLabel = false;
+
+       public EditableText(Composite parent, int style) {
+               super(parent, style);
+               editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
+               highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
+       }
+
+       public EditableText(Composite parent, int style, Item item) throws RepositoryException {
+               this(parent, style, item, false);
+       }
+
+       public EditableText(Composite parent, int style, Item item, boolean cacheImmediately) throws RepositoryException {
+               super(parent, style, item, cacheImmediately);
+               editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
+               highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
+       }
+
+       @Override
+       protected Control createControl(Composite box, String style) {
+               if (isEditing() && getEditable()) {
+                       return createText(box, style, true);
+               } else {
+                       if (useTextAsLabel) {
+                               return createTextLabel(box, style);
+                       } else {
+                               return createLabel(box, style);
+                       }
+               }
+       }
+
+       protected Label createLabel(Composite box, String style) {
+               Label lbl = new Label(box, getStyle() | SWT.WRAP);
+               lbl.setLayoutData(CmsSwtUtils.fillWidth());
+               if (style != null)
+                       CmsSwtUtils.style(lbl, style);
+               CmsSwtUtils.markup(lbl);
+               if (mouseListener != null)
+                       lbl.addMouseListener(mouseListener);
+               return lbl;
+       }
+
+       protected Text createTextLabel(Composite box, String style) {
+               Text lbl = new Text(box, getStyle() | SWT.MULTI);
+               lbl.setEditable(false);
+               lbl.setLayoutData(CmsSwtUtils.fillWidth());
+               if (style != null)
+                       CmsSwtUtils.style(lbl, style);
+               CmsSwtUtils.markup(lbl);
+               if (mouseListener != null)
+                       lbl.addMouseListener(mouseListener);
+               return lbl;
+       }
+
+       protected Text createText(Composite box, String style, boolean editable) {
+               highlight = new Composite(box, SWT.NONE);
+               highlight.setBackground(highlightColor);
+               GridData highlightGd = new GridData(SWT.FILL, SWT.FILL, false, false);
+               highlightGd.widthHint = 5;
+               highlightGd.heightHint = 3;
+               highlight.setLayoutData(highlightGd);
+
+               final Text text = new Text(box, getStyle() | SWT.MULTI | SWT.WRAP);
+               text.setEditable(editable);
+               GridData textLayoutData = CmsSwtUtils.fillWidth();
+               // textLayoutData.heightHint = preferredHeight;
+               text.setLayoutData(textLayoutData);
+               if (style != null)
+                       CmsSwtUtils.style(text, style);
+               text.setFocus();
+               return text;
+       }
+
+       @Override
+       protected void clear(boolean deep) {
+               if (highlight != null)
+                       highlight.dispose();
+               super.clear(deep);
+       }
+
+       public void setText(String text) {
+               Control child = getControl();
+               if (child instanceof Label)
+                       ((Label) child).setText(text);
+               else if (child instanceof Text)
+                       ((Text) child).setText(text);
+       }
+
+       public Text getAsText() {
+               return (Text) getControl();
+       }
+
+       public Label getAsLabel() {
+               return (Label) getControl();
+       }
+
+       public String getText() {
+               Control child = getControl();
+
+               if (child instanceof Label)
+                       return ((Label) child).getText();
+               else if (child instanceof Text)
+                       return ((Text) child).getText();
+               else
+                       throw new IllegalStateException("Unsupported control " + child.getClass());
+       }
+
+       /** @deprecated Use {@link #isEditable()} instead. */
+       @Deprecated
+       public boolean getEditable() {
+               return isEditable();
+       }
+
+       public boolean isEditable() {
+               return editable;
+       }
+
+       public void setUseTextAsLabel(boolean useTextAsLabel) {
+               this.useTextAsLabel = useTextAsLabel;
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/Img.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/Img.java
new file mode 100644 (file)
index 0000000..41063fa
--- /dev/null
@@ -0,0 +1,155 @@
+package org.argeo.cms.ui.widgets;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.api.cms.ux.CmsImageManager;
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.internal.JcrFileUploadReceiver;
+import org.argeo.cms.ui.viewers.NodePart;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.cms.ui.viewers.SectionPart;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+import org.eclipse.rap.fileupload.FileUploadHandler;
+import org.eclipse.rap.fileupload.FileUploadListener;
+import org.eclipse.rap.fileupload.FileUploadReceiver;
+import org.eclipse.rap.rwt.service.ServerPushSession;
+import org.eclipse.rap.rwt.widgets.FileUpload;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** An image within the Argeo Text framework */
+public class Img extends EditableImage implements SectionPart, NodePart {
+       private static final long serialVersionUID = 6233572783968188476L;
+
+       private final Section section;
+
+       private final CmsImageManager<Control, Node> imageManager;
+       private FileUploadHandler currentUploadHandler = null;
+       private FileUploadListener fileUploadListener;
+
+       public Img(Composite parent, int swtStyle, Node imgNode, Cms2DSize preferredImageSize) throws RepositoryException {
+               this(Section.findSection(parent), parent, swtStyle, imgNode, preferredImageSize, null);
+               setStyle(TextStyles.TEXT_IMAGE);
+       }
+
+       public Img(Composite parent, int swtStyle, Node imgNode) throws RepositoryException {
+               this(Section.findSection(parent), parent, swtStyle, imgNode, null, null);
+               setStyle(TextStyles.TEXT_IMAGE);
+       }
+
+       public Img(Composite parent, int swtStyle, Node imgNode, CmsImageManager<Control, Node> imageManager)
+                       throws RepositoryException {
+               this(Section.findSection(parent), parent, swtStyle, imgNode, null, imageManager);
+               setStyle(TextStyles.TEXT_IMAGE);
+       }
+
+       Img(Section section, Composite parent, int swtStyle, Node imgNode, Cms2DSize preferredImageSize,
+                       CmsImageManager<Control, Node> imageManager) throws RepositoryException {
+               super(parent, swtStyle, imgNode, false, preferredImageSize);
+               this.section = section;
+               this.imageManager = imageManager != null ? imageManager
+                               : (CmsImageManager<Control, Node>) CmsSwtUtils.getCmsView(section).getImageManager();
+               CmsSwtUtils.style(this, TextStyles.TEXT_IMG);
+       }
+
+       @Override
+       protected Control createControl(Composite box, String style) {
+               if (isEditing()) {
+                       try {
+                               return createImageChooser(box, style);
+                       } catch (RepositoryException e) {
+                               throw new JcrException("Cannot create image chooser", e);
+                       }
+               } else {
+                       return createLabel(box, style);
+               }
+       }
+
+       @Override
+       public synchronized void stopEditing() {
+               super.stopEditing();
+               fileUploadListener = null;
+       }
+
+       @Override
+       protected synchronized Boolean load(Control lbl) {
+               Node imgNode = getNode();
+               boolean loaded = imageManager.load(imgNode, lbl, getPreferredImageSize());
+               // getParent().layout();
+               return loaded;
+       }
+
+       protected Node getUploadFolder() {
+               return Jcr.getParent(getNode());
+       }
+
+       protected String getUploadName() {
+               Node node = getNode();
+               return Jcr.getName(node) + '[' + Jcr.getIndex(node) + ']';
+       }
+
+       protected CmsImageManager<Control, Node> getImageManager() {
+               return imageManager;
+       }
+
+       protected Control createImageChooser(Composite box, String style) throws RepositoryException {
+               JcrFileUploadReceiver receiver = new JcrFileUploadReceiver(this, getUploadFolder(), getUploadName(),
+                               imageManager);
+               if (currentUploadHandler != null)
+                       currentUploadHandler.dispose();
+               currentUploadHandler = prepareUpload(receiver);
+               final ServerPushSession pushSession = new ServerPushSession();
+               final FileUpload fileUpload = new FileUpload(box, SWT.NONE);
+               CmsSwtUtils.style(fileUpload, style);
+               fileUpload.addSelectionListener(new SelectionAdapter() {
+                       private static final long serialVersionUID = -9158471843941668562L;
+
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               pushSession.start();
+                               fileUpload.submit(currentUploadHandler.getUploadUrl());
+                       }
+               });
+               return fileUpload;
+       }
+
+       protected FileUploadHandler prepareUpload(FileUploadReceiver receiver) {
+               final FileUploadHandler uploadHandler = new FileUploadHandler(receiver);
+               if (fileUploadListener != null)
+                       uploadHandler.addUploadListener(fileUploadListener);
+               return uploadHandler;
+       }
+
+       @Override
+       public Section getSection() {
+               return section;
+       }
+
+       public void setFileUploadListener(FileUploadListener fileUploadListener) {
+               this.fileUploadListener = fileUploadListener;
+               if (currentUploadHandler != null)
+                       currentUploadHandler.addUploadListener(fileUploadListener);
+       }
+
+       @Override
+       public Node getItem() throws RepositoryException {
+               return getNode();
+       }
+
+       @Override
+       public String getPartId() {
+               return getNodeId();
+       }
+
+       @Override
+       public String toString() {
+               return "Img #" + getPartId();
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java
new file mode 100644 (file)
index 0000000..6b54c0a
--- /dev/null
@@ -0,0 +1,213 @@
+package org.argeo.cms.ui.widgets;
+
+import javax.jcr.Item;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.jcr.JcrException;
+import org.eclipse.swt.widgets.Composite;
+
+/** A composite which can (optionally) manage a JCR Item. */
+public class JcrComposite extends Composite {
+       private static final long serialVersionUID = -1447009015451153367L;
+
+       private Session session;
+
+       private String nodeId;
+       private String property = null;
+       private Node cache;
+
+       /** Regular composite constructor. No layout is set. */
+       public JcrComposite(Composite parent, int style) {
+               super(parent, style);
+               session = null;
+               nodeId = null;
+       }
+
+       public JcrComposite(Composite parent, int style, Item item) {
+               this(parent, style, item, false);
+       }
+
+       public JcrComposite(Composite parent, int style, Item item, boolean cacheImmediately) {
+               super(parent, style);
+               if (item != null)
+                       try {
+                               this.session = item.getSession();
+//                             if (!cacheImmediately && (SWT.READ_ONLY == (style & SWT.READ_ONLY))) {
+//                                     // (useless?) optimization: we only save a pointer to the session,
+//                                     // not even a reference to the item
+//                                     this.nodeId = null;
+//                             } else {
+                               Node node;
+                               Property property = null;
+                               if (item instanceof Node) {
+                                       node = (Node) item;
+                               } else {// Property
+                                       property = (Property) item;
+                                       if (property.isMultiple())// TODO manage property index
+                                               throw new UnsupportedOperationException("Multiple properties not supported yet.");
+                                       this.property = property.getName();
+                                       node = property.getParent();
+                               }
+                               this.nodeId = node.getIdentifier();
+                               if (cacheImmediately)
+                                       this.cache = node;
+//                             }
+                               setLayout(CmsSwtUtils.noSpaceGridLayout());
+                       } catch (RepositoryException e) {
+                               throw new IllegalStateException("Cannot create composite from " + item, e);
+                       }
+       }
+
+       public synchronized Node getNode() {
+               try {
+                       if (!itemIsNode())
+                               throw new IllegalStateException("Item is not a Node");
+                       return getNodeInternal();
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot get node " + nodeId, e);
+               }
+       }
+
+       private synchronized Node getNodeInternal() throws RepositoryException {
+               if (cache != null)
+                       return cache;
+               else if (session != null)
+                       if (nodeId != null)
+                               return session.getNodeByIdentifier(nodeId);
+                       else
+                               return null;
+               else
+                       return null;
+       }
+
+       public synchronized String getPropertyName() {
+               try {
+                       return getProperty().getName();
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot get property name", e);
+               }
+       }
+
+       public synchronized Node getPropertyNode() {
+               try {
+                       return getProperty().getNode();
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot get property name", e);
+               }
+       }
+
+       public synchronized Property getProperty() {
+               try {
+                       if (itemIsNode())
+                               throw new IllegalStateException("Item is not a Property");
+                       Node node = getNodeInternal();
+                       if (!node.hasProperty(property))
+                               throw new IllegalStateException("Property " + property + " is not set on " + node);
+                       return node.getProperty(property);
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot get property " + property + " from node " + nodeId, e);
+               }
+       }
+
+       public synchronized boolean itemIsNode() {
+               return property == null;
+       }
+
+       public synchronized boolean itemExists() {
+               if (session == null)
+                       return false;
+               try {
+                       Node n = session.getNodeByIdentifier(nodeId);
+                       if (!itemIsNode())
+                               return n.hasProperty(property);
+                       else
+                               return true;
+               } catch (ItemNotFoundException e) {
+                       return false;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot check whether node exists", e);
+               }
+       }
+
+       /** Set/update the cache or change the node */
+       public synchronized void setNode(Node node) {
+               if (!itemIsNode())
+                       throw new IllegalArgumentException("Cannot set a Node on a Property");
+
+               if (node == null) {// clear cache
+                       this.cache = null;
+                       return;
+               }
+
+               try {
+//                     if (session != null || session != node.getSession())// check session
+//                             throw new IllegalArgumentException("Uncompatible session");
+//                     if (session == null)
+                       session = node.getSession();
+                       if (nodeId == null || !nodeId.equals(node.getIdentifier())) {
+                               nodeId = node.getIdentifier();
+                               cache = node;
+                               itemUpdated();
+                       } else {
+                               cache = node;// set/update cache
+                       }
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException(e);
+               }
+       }
+
+       /** Set/update the cache or change the property */
+       public synchronized void setProperty(Property prop) {
+               if (itemIsNode())
+                       throw new IllegalArgumentException("Cannot set a Property on a Node");
+
+               if (prop == null) {// clear cache
+                       this.cache = null;
+                       return;
+               }
+
+               try {
+                       if (session == null || session != prop.getSession())// check session
+                               throw new IllegalArgumentException("Uncompatible session");
+
+                       Node node = prop.getNode();
+                       if (nodeId == null || !nodeId.equals(node.getIdentifier()) || !property.equals(prop.getName())) {
+                               nodeId = node.getIdentifier();
+                               property = prop.getName();
+                               cache = node;
+                               itemUpdated();
+                       } else {
+                               cache = node;// set/update cache
+                       }
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException(e);
+               }
+       }
+
+       public synchronized String getNodeId() {
+               return nodeId;
+       }
+
+       /** Change the node, does nothing if same. */
+       public synchronized void setNodeId(String nodeId) throws RepositoryException {
+               if (this.nodeId != null && this.nodeId.equals(nodeId))
+                       return;
+               this.nodeId = nodeId;
+               if (cache != null)
+                       cache = session.getNodeByIdentifier(this.nodeId);
+               itemUpdated();
+       }
+
+       protected synchronized void itemUpdated() {
+               layout();
+       }
+
+//     public Session getSession() {
+//             return session;
+//     }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/StyledControl.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/StyledControl.java
new file mode 100644 (file)
index 0000000..e3a5cb4
--- /dev/null
@@ -0,0 +1,153 @@
+package org.argeo.cms.ui.widgets;
+
+import javax.jcr.Item;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.ui.CmsUiConstants;
+import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/** Editable text part displaying styled text. */
+public abstract class StyledControl extends JcrComposite implements CmsUiConstants {
+       private static final long serialVersionUID = -6372283442330912755L;
+       private Control control;
+
+       private Composite container;
+       private Composite box;
+
+       protected MouseListener mouseListener;
+       protected FocusListener focusListener;
+
+       private Boolean editing = Boolean.FALSE;
+
+       private Composite ancestorToLayout;
+
+       public StyledControl(Composite parent, int swtStyle) {
+               super(parent, swtStyle);
+               setLayout(CmsSwtUtils.noSpaceGridLayout());
+       }
+
+       public StyledControl(Composite parent, int style, Item item) {
+               super(parent, style, item);
+       }
+
+       public StyledControl(Composite parent, int style, Item item, boolean cacheImmediately) {
+               super(parent, style, item, cacheImmediately);
+       }
+
+       protected abstract Control createControl(Composite box, String style);
+
+       protected Composite createBox() {
+               Composite box = new Composite(container, SWT.INHERIT_DEFAULT);
+               setContainerLayoutData(box);
+               box.setLayout(CmsSwtUtils.noSpaceGridLayout(3));
+               return box;
+       }
+
+       protected Composite createContainer() {
+               Composite container = new Composite(this, SWT.INHERIT_DEFAULT);
+               setContainerLayoutData(container);
+               container.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               return container;
+       }
+
+       public Control getControl() {
+               return control;
+       }
+
+       protected synchronized Boolean isEditing() {
+               return editing;
+       }
+
+       public synchronized void startEditing() {
+               assert !isEditing();
+               editing = true;
+               // int height = control.getSize().y;
+               String style = (String) EclipseUiSpecificUtils.getStyleData(control);
+               clear(false);
+               refreshControl(style);
+
+               // add the focus listener to the newly created edition control
+               if (focusListener != null)
+                       control.addFocusListener(focusListener);
+       }
+
+       public synchronized void stopEditing() {
+               assert isEditing();
+               editing = false;
+               String style = (String) EclipseUiSpecificUtils.getStyleData(control);
+               clear(false);
+               refreshControl(style);
+       }
+
+       protected void refreshControl(String style) {
+               control = createControl(box, style);
+               setControlLayoutData(control);
+               if (ancestorToLayout != null)
+                       ancestorToLayout.layout(true, true);
+               else
+                       getParent().layout(true, true);
+       }
+
+       public void setStyle(String style) {
+               Object currentStyle = null;
+               if (control != null)
+                       currentStyle = EclipseUiSpecificUtils.getStyleData(control);
+               if (currentStyle != null && currentStyle.equals(style))
+                       return;
+
+               clear(true);
+               refreshControl(style);
+
+               if (style != null) {
+                       CmsSwtUtils.style(box, style + "_box");
+                       CmsSwtUtils.style(container, style + "_container");
+               }
+       }
+
+       /** To be overridden */
+       protected void setControlLayoutData(Control control) {
+               control.setLayoutData(CmsSwtUtils.fillWidth());
+       }
+
+       /** To be overridden */
+       protected void setContainerLayoutData(Composite composite) {
+               composite.setLayoutData(CmsSwtUtils.fillWidth());
+       }
+
+       protected void clear(boolean deep) {
+               if (deep) {
+                       for (Control control : getChildren())
+                               control.dispose();
+                       container = createContainer();
+                       box = createBox();
+               } else {
+                       control.dispose();
+               }
+       }
+
+       public void setMouseListener(MouseListener mouseListener) {
+               if (this.mouseListener != null && control != null)
+                       control.removeMouseListener(this.mouseListener);
+               this.mouseListener = mouseListener;
+               if (control != null && this.mouseListener != null)
+                       control.addMouseListener(mouseListener);
+       }
+
+       public void setFocusListener(FocusListener focusListener) {
+               if (this.focusListener != null && control != null)
+                       control.removeFocusListener(this.focusListener);
+               this.focusListener = focusListener;
+               if (control != null && this.focusListener != null)
+                       control.addFocusListener(focusListener);
+       }
+
+       public void setAncestorToLayout(Composite ancestorToLayout) {
+               this.ancestorToLayout = ancestorToLayout;
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/TextStyles.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/TextStyles.java
new file mode 100644 (file)
index 0000000..e461ed0
--- /dev/null
@@ -0,0 +1,37 @@
+package org.argeo.cms.ui.widgets;
+
+/** Styles references in the CSS. */
+public interface TextStyles {
+       /** The whole page area */
+       public final static String TEXT_AREA = "text_area";
+       /** Area providing controls for editing text */
+       public final static String TEXT_EDITOR_HEADER = "text_editor_header";
+       /** The styled composite for editing the text */
+       public final static String TEXT_STYLED_COMPOSITE = "text_styled_composite";
+       /** A section */
+       public final static String TEXT_SECTION = "text_section";
+       /** A paragraph */
+       public final static String TEXT_PARAGRAPH = "text_paragraph";
+       /** An image */
+       public final static String TEXT_IMG = "text_img";
+       /** The dialog to edit styled paragraph */
+       public final static String TEXT_STYLED_TOOLS_DIALOG = "text_styled_tools_dialog";
+
+       /*
+        * DEFAULT TEXT STYLES
+        */
+       /** Default style for text body */
+       public final static String TEXT_DEFAULT = "text_default";
+       /** Fixed-width, typically code */
+       public final static String TEXT_PRE = "text_pre";
+       /** Quote */
+       public final static String TEXT_QUOTE = "text_quote";
+       /** Title */
+       public final static String TEXT_TITLE = "text_title";
+       /** Header (to be dynamically completed with the depth, e.g. text_h1) */
+       public final static String TEXT_H = "text_h";
+
+       /** Default style for images */
+       public final static String TEXT_IMAGE = "text_image";
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/package-info.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/cms/ui/widgets/package-info.java
new file mode 100644 (file)
index 0000000..514f753
--- /dev/null
@@ -0,0 +1,2 @@
+/** Argeo CMS generic widgets, based on SWT. */
+package org.argeo.cms.ui.widgets;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/AbstractNodeContentProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/AbstractNodeContentProvider.java
new file mode 100644 (file)
index 0000000..fdafa98
--- /dev/null
@@ -0,0 +1,138 @@
+package org.argeo.eclipse.ui.jcr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.eclipse.ui.AbstractTreeContentProvider;
+import org.argeo.eclipse.ui.EclipseUiException;
+
+/** Canonical implementation of tree content provider manipulating JCR nodes. */
+public abstract class AbstractNodeContentProvider extends
+               AbstractTreeContentProvider {
+       private static final long serialVersionUID = -4905836490027272569L;
+
+       private final static CmsLog log = CmsLog
+                       .getLog(AbstractNodeContentProvider.class);
+
+       private Session session;
+
+       public AbstractNodeContentProvider(Session session) {
+               this.session = session;
+       }
+
+       /**
+        * Whether this path is a base path (and thus has no parent). By default it
+        * returns true if path is '/' (root node)
+        */
+       protected Boolean isBasePath(String path) {
+               // root node
+               return path.equals("/");
+       }
+
+       @Override
+       public Object[] getChildren(Object element) {
+               Object[] children;
+               if (element instanceof Node) {
+                       try {
+                               Node node = (Node) element;
+                               children = getChildren(node);
+                       } catch (RepositoryException e) {
+                               throw new EclipseUiException("Cannot get children of " + element, e);
+                       }
+               } else if (element instanceof WrappedNode) {
+                       WrappedNode wrappedNode = (WrappedNode) element;
+                       try {
+                               children = getChildren(wrappedNode.getNode());
+                       } catch (RepositoryException e) {
+                               throw new EclipseUiException("Cannot get children of "
+                                               + wrappedNode, e);
+                       }
+               } else if (element instanceof NodesWrapper) {
+                       NodesWrapper node = (NodesWrapper) element;
+                       children = node.getChildren();
+               } else {
+                       children = super.getChildren(element);
+               }
+
+               children = sort(element, children);
+               return children;
+       }
+
+       /** Do not sort by default. To be overidden to provide custom sort. */
+       protected Object[] sort(Object parent, Object[] children) {
+               return children;
+       }
+
+       /**
+        * To be overridden in order to filter out some nodes. Does nothing by
+        * default. The provided list is a temporary one and can thus be modified
+        * directly . (e.g. via an iterator)
+        */
+       protected List<Node> filterChildren(List<Node> children)
+                       throws RepositoryException {
+               return children;
+       }
+
+       protected Object[] getChildren(Node node) throws RepositoryException {
+               List<Node> nodes = new ArrayList<Node>();
+               for (NodeIterator nit = node.getNodes(); nit.hasNext();)
+                       nodes.add(nit.nextNode());
+               nodes = filterChildren(nodes);
+               return nodes.toArray();
+       }
+
+       @Override
+       public Object getParent(Object element) {
+               if (element instanceof Node) {
+                       Node node = (Node) element;
+                       try {
+                               String path = node.getPath();
+                               if (isBasePath(path))
+                                       return null;
+                               else
+                                       return node.getParent();
+                       } catch (RepositoryException e) {
+                               log.warn("Cannot get parent of " + element + ": " + e);
+                               return null;
+                       }
+               } else if (element instanceof WrappedNode) {
+                       WrappedNode wrappedNode = (WrappedNode) element;
+                       return wrappedNode.getParent();
+               } else if (element instanceof NodesWrapper) {
+                       NodesWrapper nodesWrapper = (NodesWrapper) element;
+                       return this.getParent(nodesWrapper.getNode());
+               }
+               return super.getParent(element);
+       }
+
+       @Override
+       public boolean hasChildren(Object element) {
+               try {
+                       if (element instanceof Node) {
+                               Node node = (Node) element;
+                               return node.hasNodes();
+                       } else if (element instanceof WrappedNode) {
+                               WrappedNode wrappedNode = (WrappedNode) element;
+                               return wrappedNode.getNode().hasNodes();
+                       } else if (element instanceof NodesWrapper) {
+                               NodesWrapper nodesWrapper = (NodesWrapper) element;
+                               return nodesWrapper.hasChildren();
+                       }
+
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot check whether " + element
+                                       + " has children", e);
+               }
+               return super.hasChildren(element);
+       }
+
+       public Session getSession() {
+               return session;
+       }
+}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/AsyncUiEventListener.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/AsyncUiEventListener.java
new file mode 100644 (file)
index 0000000..b880a63
--- /dev/null
@@ -0,0 +1,83 @@
+package org.argeo.eclipse.ui.jcr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * {@link EventListener} which simplifies running actions within the UI thread.
+ */
+public abstract class AsyncUiEventListener implements EventListener {
+       // private final static Log logSuper = LogFactory
+       // .getLog(AsyncUiEventListener.class);
+       private final CmsLog logThis = CmsLog.getLog(getClass());
+
+       private final Display display;
+
+       public AsyncUiEventListener(Display display) {
+               super();
+               this.display = display;
+       }
+
+       /** Called asynchronously in the UI thread. */
+       protected abstract void onEventInUiThread(List<Event> events) throws RepositoryException;
+
+       /**
+        * Whether these events should be processed in the UI or skipped with no UI
+        * job created.
+        */
+       protected Boolean willProcessInUiThread(List<Event> events) throws RepositoryException {
+               return true;
+       }
+
+       protected CmsLog getLog() {
+               return logThis;
+       }
+
+       public final void onEvent(final EventIterator eventIterator) {
+               final List<Event> events = new ArrayList<Event>();
+               while (eventIterator.hasNext())
+                       events.add(eventIterator.nextEvent());
+
+               if (logThis.isTraceEnabled())
+                       logThis.trace("Received " + events.size() + " events");
+
+               try {
+                       if (!willProcessInUiThread(events))
+                               return;
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot test skip events " + events, e);
+               }
+
+               // Job job = new Job("JCR Events") {
+               // protected IStatus run(IProgressMonitor monitor) {
+               // if (display.isDisposed()) {
+               // logSuper.warn("Display is disposed cannot update UI");
+               // return Status.CANCEL_STATUS;
+               // }
+
+               if (!display.isDisposed())
+                       display.asyncExec(new Runnable() {
+                               public void run() {
+                                       try {
+                                               onEventInUiThread(events);
+                                       } catch (RepositoryException e) {
+                                               throw new EclipseUiException("Cannot process events " + events, e);
+                                       }
+                               }
+                       });
+
+               // return Status.OK_STATUS;
+               // }
+               // };
+               // job.schedule();
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/DefaultNodeLabelProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/DefaultNodeLabelProvider.java
new file mode 100644 (file)
index 0000000..22ffeaf
--- /dev/null
@@ -0,0 +1,82 @@
+package org.argeo.eclipse.ui.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * Default label provider to manage node and corresponding UI objects. It
+ * provides reasonable overwrite-able default for known JCR types.
+ */
+public class DefaultNodeLabelProvider extends ColumnLabelProvider {
+       private static final long serialVersionUID = 1216182332792151235L;
+
+       public String getText(Object element) {
+               try {
+                       if (element instanceof Node) {
+                               return getText((Node) element);
+                       } else if (element instanceof WrappedNode) {
+                               return getText(((WrappedNode) element).getNode());
+                       } else if (element instanceof NodesWrapper) {
+                               return getText(((NodesWrapper) element).getNode());
+                       }
+                       return super.getText(element);
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot get text for of " + element, e);
+               }
+       }
+
+       protected String getText(Node node) throws RepositoryException {
+               if (node.isNodeType(NodeType.MIX_TITLE)
+                               && node.hasProperty(Property.JCR_TITLE))
+                       return node.getProperty(Property.JCR_TITLE).getString();
+               else
+                       return node.getName();
+       }
+
+       @Override
+       public Image getImage(Object element) {
+               try {
+                       if (element instanceof Node) {
+                               return getImage((Node) element);
+                       } else if (element instanceof WrappedNode) {
+                               return getImage(((WrappedNode) element).getNode());
+                       } else if (element instanceof NodesWrapper) {
+                               return getImage(((NodesWrapper) element).getNode());
+                       }
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot retrieve image for " + element, e);
+               }
+               return super.getImage(element);
+       }
+
+       protected Image getImage(Node node) throws RepositoryException {
+               // FIXME who uses that?
+               return null;
+       }
+
+       @Override
+       public String getToolTipText(Object element) {
+               try {
+                       if (element instanceof Node) {
+                               return getToolTipText((Node) element);
+                       } else if (element instanceof WrappedNode) {
+                               return getToolTipText(((WrappedNode) element).getNode());
+                       } else if (element instanceof NodesWrapper) {
+                               return getToolTipText(((NodesWrapper) element).getNode());
+                       }
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot get tooltip for " + element, e);
+               }
+               return super.getToolTipText(element);
+       }
+
+       protected String getToolTipText(Node node) throws RepositoryException {
+               return null;
+       }
+}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/JcrUiUtils.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/JcrUiUtils.java
new file mode 100644 (file)
index 0000000..420154b
--- /dev/null
@@ -0,0 +1,149 @@
+package org.argeo.eclipse.ui.jcr;
+
+import java.util.Calendar;
+
+import javax.jcr.Node;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.jcr.lists.NodeViewerComparator;
+import org.argeo.eclipse.ui.jcr.lists.RowViewerComparator;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Table;
+
+/** Utility methods to simplify UI development using SWT (or RWT), jface  and JCR. */
+public class JcrUiUtils {
+
+       /**
+        * Centralizes management of updating property value. Among other to avoid
+        * infinite loop when the new value is the same as the ones that is already
+        * stored in JCR.
+        * 
+        * @return true if the value as changed
+        */
+       public static boolean setJcrProperty(Node node, String propName,
+                       int propertyType, Object value) {
+               try {
+                       switch (propertyType) {
+                       case PropertyType.STRING:
+                               if ("".equals((String) value)
+                                               && (!node.hasProperty(propName) || node
+                                                               .hasProperty(propName)
+                                                               && "".equals(node.getProperty(propName)
+                                                                               .getString())))
+                                       // workaround the fact that the Text widget value cannot be
+                                       // set to null
+                                       return false;
+                               else if (node.hasProperty(propName)
+                                               && node.getProperty(propName).getString()
+                                                               .equals((String) value))
+                                       // nothing changed yet
+                                       return false;
+                               else {
+                                       node.setProperty(propName, (String) value);
+                                       return true;
+                               }
+                       case PropertyType.BOOLEAN:
+                               if (node.hasProperty(propName)
+                                               && node.getProperty(propName).getBoolean() == (Boolean) value)
+                                       // nothing changed yet
+                                       return false;
+                               else {
+                                       node.setProperty(propName, (Boolean) value);
+                                       return true;
+                               }
+                       case PropertyType.DATE:
+                               if (node.hasProperty(propName)
+                                               && node.getProperty(propName).getDate()
+                                                               .equals((Calendar) value))
+                                       // nothing changed yet
+                                       return false;
+                               else {
+                                       node.setProperty(propName, (Calendar) value);
+                                       return true;
+                               }
+                       case PropertyType.LONG:
+                               Long lgValue = (Long) value;
+
+                               if (lgValue == null)
+                                       lgValue = 0L;
+
+                               if (node.hasProperty(propName)
+                                               && node.getProperty(propName).getLong() == lgValue)
+                                       // nothing changed yet
+                                       return false;
+                               else {
+                                       node.setProperty(propName, lgValue);
+                                       return true;
+                               }
+
+                       default:
+                               throw new EclipseUiException("Unimplemented property save");
+                       }
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Unexpected error while setting property",
+                                       re);
+               }
+       }
+
+       /**
+        * Creates a new selection adapter in order to provide sorting abitily on a
+        * SWT Table that display a row list
+        **/
+       public static SelectionAdapter getRowSelectionAdapter(final int index,
+                       final int propertyType, final String selectorName,
+                       final String propertyName, final RowViewerComparator comparator,
+                       final TableViewer viewer) {
+               SelectionAdapter selectionAdapter = new SelectionAdapter() {
+                       private static final long serialVersionUID = -5738918304901437720L;
+
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               Table table = viewer.getTable();
+                               comparator.setColumn(propertyType, selectorName, propertyName);
+                               int dir = table.getSortDirection();
+                               if (table.getSortColumn() == table.getColumn(index)) {
+                                       dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+                               } else {
+                                       dir = SWT.DOWN;
+                               }
+                               table.setSortDirection(dir);
+                               table.setSortColumn(table.getColumn(index));
+                               viewer.refresh();
+                       }
+               };
+               return selectionAdapter;
+       }
+
+       /**
+        * Creates a new selection adapter in order to provide sorting abitily on a
+        * swt table that display a row list
+        **/
+       public static SelectionAdapter getNodeSelectionAdapter(final int index,
+                       final int propertyType, final String propertyName,
+                       final NodeViewerComparator comparator, final TableViewer viewer) {
+               SelectionAdapter selectionAdapter = new SelectionAdapter() {
+                       private static final long serialVersionUID = -1683220869195484625L;
+
+                       @Override
+                       public void widgetSelected(SelectionEvent e) {
+                               Table table = viewer.getTable();
+                               comparator.setColumn(propertyType, propertyName);
+                               int dir = table.getSortDirection();
+                               if (table.getSortColumn() == table.getColumn(index)) {
+                                       dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
+                               } else {
+                                       dir = SWT.DOWN;
+                               }
+                               table.setSortDirection(dir);
+                               table.setSortColumn(table.getColumn(index));
+                               viewer.refresh();
+                       }
+               };
+               return selectionAdapter;
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/NodeColumnLabelProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/NodeColumnLabelProvider.java
new file mode 100644 (file)
index 0000000..7e12bec
--- /dev/null
@@ -0,0 +1,123 @@
+package org.argeo.eclipse.ui.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+
+/** Simplifies writing JCR-based column label provider. */
+public class NodeColumnLabelProvider extends ColumnLabelProvider {
+       private static final long serialVersionUID = -6586692836928505358L;
+
+       protected String getNodeText(Node node) throws RepositoryException {
+               return super.getText(node);
+       }
+
+       protected String getNodeToolTipText(Node node) throws RepositoryException {
+               return super.getToolTipText(node);
+       }
+
+       protected Image getNodeImage(Node node) throws RepositoryException {
+               return super.getImage(node);
+       }
+
+       protected Font getNodeFont(Node node) throws RepositoryException {
+               return super.getFont(node);
+       }
+
+       public Color getNodeBackground(Node node) throws RepositoryException {
+               return super.getBackground(node);
+       }
+
+       public Color getNodeForeground(Node node) throws RepositoryException {
+               return super.getForeground(node);
+       }
+
+       @Override
+       public String getText(Object element) {
+               try {
+                       if (element instanceof Node)
+                               return getNodeText((Node) element);
+                       else if (element instanceof NodeElement)
+                               return getNodeText(((NodeElement) element).getNode());
+                       else
+                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Repository exception when accessing " + element, e);
+               }
+       }
+
+       @Override
+       public Image getImage(Object element) {
+               try {
+                       if (element instanceof Node)
+                               return getNodeImage((Node) element);
+                       else if (element instanceof NodeElement)
+                               return getNodeImage(((NodeElement) element).getNode());
+                       else
+                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Repository exception when accessing " + element, e);
+               }
+       }
+
+       @Override
+       public String getToolTipText(Object element) {
+               try {
+                       if (element instanceof Node)
+                               return getNodeToolTipText((Node) element);
+                       else if (element instanceof NodeElement)
+                               return getNodeToolTipText(((NodeElement) element).getNode());
+                       else
+                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Repository exception when accessing " + element, e);
+               }
+       }
+
+       @Override
+       public Font getFont(Object element) {
+               try {
+                       if (element instanceof Node)
+                               return getNodeFont((Node) element);
+                       else if (element instanceof NodeElement)
+                               return getNodeFont(((NodeElement) element).getNode());
+                       else
+                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Repository exception when accessing " + element, e);
+               }
+       }
+
+       @Override
+       public Color getBackground(Object element) {
+               try {
+                       if (element instanceof Node)
+                               return getNodeBackground((Node) element);
+                       else if (element instanceof NodeElement)
+                               return getNodeBackground(((NodeElement) element).getNode());
+                       else
+                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Repository exception when accessing " + element, e);
+               }
+       }
+
+       @Override
+       public Color getForeground(Object element) {
+               try {
+                       if (element instanceof Node)
+                               return getNodeForeground((Node) element);
+                       else if (element instanceof NodeElement)
+                               return getNodeForeground(((NodeElement) element).getNode());
+                       else
+                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Repository exception when accessing " + element, e);
+               }
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/NodeElement.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/NodeElement.java
new file mode 100644 (file)
index 0000000..787c92e
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.eclipse.ui.jcr;
+
+import javax.jcr.Node;
+
+/** An element which is related to a JCR {@link Node}. */
+public interface NodeElement {
+       Node getNode();
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/NodeElementComparer.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/NodeElementComparer.java
new file mode 100644 (file)
index 0000000..2f3d64d
--- /dev/null
@@ -0,0 +1,36 @@
+package org.argeo.eclipse.ui.jcr;\r
+\r
+import javax.jcr.Node;\r
+import javax.jcr.RepositoryException;\r
+\r
+import org.argeo.eclipse.ui.EclipseUiException;\r
+import org.eclipse.jface.viewers.IElementComparer;\r
+\r
+/** Element comparer for JCR node, to be used in JFace viewers. */\r
+public class NodeElementComparer implements IElementComparer {\r
+\r
+       public boolean equals(Object a, Object b) {\r
+               try {\r
+                       if ((a instanceof Node) && (b instanceof Node)) {\r
+                               Node nodeA = (Node) a;\r
+                               Node nodeB = (Node) b;\r
+                               return nodeA.getIdentifier().equals(nodeB.getIdentifier());\r
+                       } else {\r
+                               return a.equals(b);\r
+                       }\r
+               } catch (RepositoryException e) {\r
+                       throw new EclipseUiException("Cannot compare nodes", e);\r
+               }\r
+       }\r
+\r
+       public int hashCode(Object element) {\r
+               try {\r
+                       if (element instanceof Node)\r
+                               return ((Node) element).getIdentifier().hashCode();\r
+                       return element.hashCode();\r
+               } catch (RepositoryException e) {\r
+                       throw new EclipseUiException("Cannot get hash code", e);\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/NodesWrapper.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/NodesWrapper.java
new file mode 100644 (file)
index 0000000..2f808a5
--- /dev/null
@@ -0,0 +1,71 @@
+package org.argeo.eclipse.ui.jcr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+
+/**
+ * Element of tree which is based on a node, but whose children are not
+ * necessarily this node children.
+ */
+public class NodesWrapper {
+       private final Node node;
+
+       public NodesWrapper(Node node) {
+               super();
+               this.node = node;
+       }
+
+       protected NodeIterator getNodeIterator() throws RepositoryException {
+               return node.getNodes();
+       }
+
+       protected List<WrappedNode> getWrappedNodes() throws RepositoryException {
+               List<WrappedNode> nodes = new ArrayList<WrappedNode>();
+               for (NodeIterator nit = getNodeIterator(); nit.hasNext();)
+                       nodes.add(new WrappedNode(this, nit.nextNode()));
+               return nodes;
+       }
+
+       public Object[] getChildren() {
+               try {
+                       return getWrappedNodes().toArray();
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot get wrapped children", e);
+               }
+       }
+
+       /**
+        * @return true by default because we don't want to compute the wrapped
+        *         nodes twice
+        */
+       public Boolean hasChildren() {
+               return true;
+       }
+
+       public Node getNode() {
+               return node;
+       }
+
+       @Override
+       public int hashCode() {
+               return node.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj instanceof NodesWrapper)
+                       return node.equals(((NodesWrapper) obj).getNode());
+               else
+                       return false;
+       }
+
+       public String toString() {
+               return "nodes wrapper based on " + node;
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/QueryTableContentProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/QueryTableContentProvider.java
new file mode 100644 (file)
index 0000000..934fa67
--- /dev/null
@@ -0,0 +1,35 @@
+package org.argeo.eclipse.ui.jcr;
+
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.query.Query;
+
+import org.argeo.jcr.JcrException;
+import org.argeo.jcr.JcrUtils;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/** Content provider based on a JCR {@link Query}. */
+public class QueryTableContentProvider implements IStructuredContentProvider {
+       private static final long serialVersionUID = 760371460907204722L;
+
+       @Override
+       public void dispose() {
+       }
+
+       @Override
+       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+       }
+
+       @Override
+       public Object[] getElements(Object inputElement) {
+               Query query = (Query) inputElement;
+               try {
+                       NodeIterator nit = query.execute().getNodes();
+                       return JcrUtils.nodeIteratorToList(nit).toArray();
+               } catch (RepositoryException e) {
+                       throw new JcrException(e);
+               }
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/RowColumnLabelProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/RowColumnLabelProvider.java
new file mode 100644 (file)
index 0000000..70c71ef
--- /dev/null
@@ -0,0 +1,111 @@
+package org.argeo.eclipse.ui.jcr;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.query.Row;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+
+/** Simplifies writing JCR-based column label provider. */
+public class RowColumnLabelProvider extends ColumnLabelProvider {
+       private static final long serialVersionUID = -6586692836928505358L;
+
+       protected String getRowText(Row row) throws RepositoryException {
+               return super.getText(row);
+       }
+
+       protected String getRowToolTipText(Row row) throws RepositoryException {
+               return super.getToolTipText(row);
+       }
+
+       protected Image getRowImage(Row row) throws RepositoryException {
+               return super.getImage(row);
+       }
+
+       protected Font getRowFont(Row row) throws RepositoryException {
+               return super.getFont(row);
+       }
+
+       public Color getRowBackground(Row row) throws RepositoryException {
+               return super.getBackground(row);
+       }
+
+       public Color getRowForeground(Row row) throws RepositoryException {
+               return super.getForeground(row);
+       }
+
+       @Override
+       public String getText(Object element) {
+               try {
+                       if (element instanceof Row)
+                               return getRowText((Row) element);
+                       else
+                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Repository exception when accessing " + element, e);
+               }
+       }
+
+       @Override
+       public Image getImage(Object element) {
+               try {
+                       if (element instanceof Row)
+                               return getRowImage((Row) element);
+                       else
+                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Repository exception when accessing " + element, e);
+               }
+       }
+
+       @Override
+       public String getToolTipText(Object element) {
+               try {
+                       if (element instanceof Row)
+                               return getRowToolTipText((Row) element);
+                       else
+                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Repository exception when accessing " + element, e);
+               }
+       }
+
+       @Override
+       public Font getFont(Object element) {
+               try {
+                       if (element instanceof Row)
+                               return getRowFont((Row) element);
+                       else
+                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Repository exception when accessing " + element, e);
+               }
+       }
+
+       @Override
+       public Color getBackground(Object element) {
+               try {
+                       if (element instanceof Row)
+                               return getRowBackground((Row) element);
+                       else
+                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Repository exception when accessing " + element, e);
+               }
+       }
+
+       @Override
+       public Color getForeground(Object element) {
+               try {
+                       if (element instanceof Row)
+                               return getRowForeground((Row) element);
+                       else
+                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Repository exception when accessing " + element, e);
+               }
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/SimpleNodeContentProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/SimpleNodeContentProvider.java
new file mode 100644 (file)
index 0000000..cb235d7
--- /dev/null
@@ -0,0 +1,59 @@
+package org.argeo.eclipse.ui.jcr;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.jcr.JcrUtils;
+
+/** Simple JCR node content provider taking a list of String as base path. */
+public class SimpleNodeContentProvider extends AbstractNodeContentProvider {
+       private static final long serialVersionUID = -8245193308831384269L;
+       private final List<String> basePaths;
+       private Boolean mkdirs = false;
+
+       public SimpleNodeContentProvider(Session session, String... basePaths) {
+               this(session, Arrays.asList(basePaths));
+       }
+
+       public SimpleNodeContentProvider(Session session, List<String> basePaths) {
+               super(session);
+               this.basePaths = basePaths;
+       }
+
+       @Override
+       protected Boolean isBasePath(String path) {
+               if (basePaths.contains(path))
+                       return true;
+               return super.isBasePath(path);
+       }
+
+       public Object[] getElements(Object inputElement) {
+               try {
+                       List<Node> baseNodes = new ArrayList<Node>();
+                       for (String basePath : basePaths)
+                               if (mkdirs && !getSession().itemExists(basePath))
+                                       baseNodes.add(JcrUtils.mkdirs(getSession(), basePath));
+                               else
+                                       baseNodes.add(getSession().getNode(basePath));
+                       return baseNodes.toArray();
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot get base nodes for " + basePaths,
+                                       e);
+               }
+       }
+
+       public List<String> getBasePaths() {
+               return basePaths;
+       }
+
+       public void setMkdirs(Boolean mkdirs) {
+               this.mkdirs = mkdirs;
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/VersionColumnLabelProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/VersionColumnLabelProvider.java
new file mode 100644 (file)
index 0000000..1ce3154
--- /dev/null
@@ -0,0 +1,80 @@
+package org.argeo.eclipse.ui.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.version.Version;
+
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.swt.graphics.Image;
+
+/** Simplifies writing JCR-based column label provider. */
+public class VersionColumnLabelProvider extends ColumnLabelProvider {
+       private static final long serialVersionUID = -6117690082313161159L;
+
+       protected String getVersionText(Version version) throws RepositoryException {
+               return super.getText(version);
+       }
+
+       protected String getVersionToolTipText(Version version) throws RepositoryException {
+               return super.getToolTipText(version);
+       }
+
+       protected Image getVersionImage(Version version) throws RepositoryException {
+               return super.getImage(version);
+       }
+
+       protected String getUserName(Version version) throws RepositoryException {
+               Node node = version.getFrozenNode();
+               if(node.hasProperty(Property.JCR_LAST_MODIFIED_BY))
+                       return node.getProperty(Property.JCR_LAST_MODIFIED_BY).getString();
+               if(node.hasProperty(Property.JCR_CREATED_BY))
+                       return node.getProperty(Property.JCR_CREATED_BY).getString();
+               return null;
+       }
+       
+//     protected String getActivityTitle(Version version) throws RepositoryException {
+//             Node activity = getActivity(version);
+//             if (activity == null)
+//                     return null;
+//             if (activity.hasProperty("jcr:activityTitle"))
+//                     return activity.getProperty("jcr:activityTitle").getString();
+//             else
+//                     return activity.getName();
+//     }
+//
+//     protected Node getActivity(Version version) throws RepositoryException {
+//             if (version.hasProperty(Property.JCR_ACTIVITY)) {
+//                     return version.getProperty(Property.JCR_ACTIVITY).getNode();
+//             } else
+//                     return null;
+//     }
+
+       @Override
+       public String getText(Object element) {
+               try {
+                       return getVersionText((Version) element);
+               } catch (RepositoryException e) {
+                       throw new RuntimeException("Runtime repository exception when accessing " + element, e);
+               }
+       }
+
+       @Override
+       public Image getImage(Object element) {
+               try {
+                       return getVersionImage((Version) element);
+               } catch (RepositoryException e) {
+                       throw new RuntimeException("Runtime repository exception when accessing " + element, e);
+               }
+       }
+
+       @Override
+       public String getToolTipText(Object element) {
+               try {
+                       return getVersionToolTipText((Version) element);
+               } catch (RepositoryException e) {
+                       throw new RuntimeException("Runtime repository exception when accessing " + element, e);
+               }
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/VersionHistoryContentProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/VersionHistoryContentProvider.java
new file mode 100644 (file)
index 0000000..32e5d30
--- /dev/null
@@ -0,0 +1,27 @@
+package org.argeo.eclipse.ui.jcr;
+
+import javax.jcr.version.VersionHistory;
+
+import org.argeo.jcr.Jcr;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/** Content provider based on a {@link VersionHistory}. */
+public class VersionHistoryContentProvider implements IStructuredContentProvider {
+       private static final long serialVersionUID = -4921107883428887012L;
+
+       @Override
+       public void dispose() {
+       }
+
+       @Override
+       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+       }
+
+       @Override
+       public Object[] getElements(Object inputElement) {
+               VersionHistory versionHistory = (VersionHistory) inputElement;
+               return Jcr.getLinearVersions(versionHistory).toArray();
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/WrappedNode.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/WrappedNode.java
new file mode 100644 (file)
index 0000000..43df1fe
--- /dev/null
@@ -0,0 +1,41 @@
+package org.argeo.eclipse.ui.jcr;
+
+import javax.jcr.Node;
+
+/** Wrap a node (created from a {@link NodesWrapper}) */
+public class WrappedNode {
+       private final NodesWrapper parent;
+       private final Node node;
+
+       public WrappedNode(NodesWrapper parent, Node node) {
+               super();
+               this.parent = parent;
+               this.node = node;
+       }
+
+       public NodesWrapper getParent() {
+               return parent;
+       }
+
+       public Node getNode() {
+               return node;
+       }
+
+       public String toString() {
+               return "wrapped " + node;
+       }
+
+       @Override
+       public int hashCode() {
+               return node.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj instanceof WrappedNode)
+                       return node.equals(((WrappedNode) obj).getNode());
+               else
+                       return false;
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/JcrColumnDefinition.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/JcrColumnDefinition.java
new file mode 100644 (file)
index 0000000..c5dd733
--- /dev/null
@@ -0,0 +1,116 @@
+package org.argeo.eclipse.ui.jcr.lists;
+
+import javax.jcr.Node;
+import javax.jcr.query.Row;
+
+import org.argeo.eclipse.ui.ColumnDefinition;
+
+/**
+ * Utility object to manage column in various tables and extracts displaying
+ * data from JCR
+ */
+public class JcrColumnDefinition extends ColumnDefinition {
+       private final static int DEFAULT_COLUMN_SIZE = 120;
+
+       private String selectorName;
+       private String propertyName;
+       private int propertyType;
+       private int columnSize;
+
+       /**
+        * Use this kind of columns to configure a table that displays JCR
+        * {@link Row}
+        * 
+        * @param selectorName
+        * @param propertyName
+        * @param propertyType
+        * @param headerLabel
+        */
+       public JcrColumnDefinition(String selectorName, String propertyName,
+                       int propertyType, String headerLabel) {
+               super(new SimpleJcrRowLabelProvider(selectorName, propertyName),
+                               headerLabel);
+               this.selectorName = selectorName;
+               this.propertyName = propertyName;
+               this.propertyType = propertyType;
+               this.columnSize = DEFAULT_COLUMN_SIZE;
+       }
+
+       /**
+        * Use this kind of columns to configure a table that displays JCR
+        * {@link Row}
+        * 
+        * @param selectorName
+        * @param propertyName
+        * @param propertyType
+        * @param headerLabel
+        * @param columnSize
+        */
+       public JcrColumnDefinition(String selectorName, String propertyName,
+                       int propertyType, String headerLabel, int columnSize) {
+               super(new SimpleJcrRowLabelProvider(selectorName, propertyName),
+                               headerLabel, columnSize);
+               this.selectorName = selectorName;
+               this.propertyName = propertyName;
+               this.propertyType = propertyType;
+               this.columnSize = columnSize;
+       }
+
+       /**
+        * Use this kind of columns to configure a table that displays JCR
+        * {@link Node}
+        * 
+        * @param propertyName
+        * @param propertyType
+        * @param headerLabel
+        * @param columnSize
+        */
+       public JcrColumnDefinition(String propertyName, int propertyType,
+                       String headerLabel, int columnSize) {
+               super(new SimpleJcrNodeLabelProvider(propertyName), headerLabel,
+                               columnSize);
+               this.propertyName = propertyName;
+               this.propertyType = propertyType;
+               this.columnSize = columnSize;
+       }
+
+       public String getSelectorName() {
+               return selectorName;
+       }
+
+       public void setSelectorName(String selectorName) {
+               this.selectorName = selectorName;
+       }
+
+       public String getPropertyName() {
+               return propertyName;
+       }
+
+       public void setPropertyName(String propertyName) {
+               this.propertyName = propertyName;
+       }
+
+       public int getPropertyType() {
+               return propertyType;
+       }
+
+       public void setPropertyType(int propertyType) {
+               this.propertyType = propertyType;
+       }
+
+       public int getColumnSize() {
+               return columnSize;
+       }
+
+       public void setColumnSize(int columnSize) {
+               this.columnSize = columnSize;
+       }
+
+       public String getHeaderLabel() {
+               return super.getLabel();
+       }
+
+       public void setHeaderLabel(String headerLabel) {
+               super.setLabel(headerLabel);
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/NodeViewerComparator.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/NodeViewerComparator.java
new file mode 100644 (file)
index 0000000..341b3ab
--- /dev/null
@@ -0,0 +1,190 @@
+package org.argeo.eclipse.ui.jcr.lists;
+
+import java.math.BigDecimal;
+import java.util.Calendar;
+
+import javax.jcr.Node;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+
+/**
+ * Base comparator to enable ordering on Table or Tree viewer that display Jcr
+ * Nodes.
+ * 
+ * Note that the following snippet must be added before setting the comparator
+ * to the corresponding control: <code>
+ * // IMPORTANT: initialize comparator before setting it
+ * JcrColumnDefinition firstCol = colDefs.get(0);
+ * comparator.setColumn(firstCol.getPropertyType(),
+ * firstCol.getPropertyName());
+ * viewer.setComparator(comparator); </code>
+ */
+public class NodeViewerComparator extends ViewerComparator {
+       private static final long serialVersionUID = -7782916140737279027L;
+
+       protected String propertyName;
+
+       protected int propertyType;
+       public static final int ASCENDING = 0, DESCENDING = 1;
+       protected int direction = DESCENDING;
+
+       public NodeViewerComparator() {
+       }
+
+       /**
+        * e1 and e2 must both be Jcr nodes.
+        * 
+        * @param viewer
+        * @param e1
+        * @param e2
+        * @return
+        */
+       @Override
+       public int compare(Viewer viewer, Object e1, Object e2) {
+               int rc = 0;
+               long lc = 0;
+
+               try {
+                       Node n1 = (Node) e1;
+                       Node n2 = (Node) e2;
+
+                       Value v1 = null;
+                       Value v2 = null;
+                       if (n1.hasProperty(propertyName))
+                               v1 = n1.getProperty(propertyName).getValue();
+                       if (n2.hasProperty(propertyName))
+                               v2 = n2.getProperty(propertyName).getValue();
+
+                       if (v2 == null && v1 == null)
+                               return 0;
+                       else if (v2 == null)
+                               return -1;
+                       else if (v1 == null)
+                               return 1;
+
+                       switch (propertyType) {
+                       case PropertyType.STRING:
+                               rc = v1.getString().compareTo(v2.getString());
+                               break;
+                       case PropertyType.BOOLEAN:
+                               boolean b1 = v1.getBoolean();
+                               boolean b2 = v2.getBoolean();
+                               if (b1 == b2)
+                                       rc = 0;
+                               else
+                                       // we assume true is greater than false
+                                       rc = b1 ? 1 : -1;
+                               break;
+                       case PropertyType.DATE:
+                               Calendar c1 = v1.getDate();
+                               Calendar c2 = v2.getDate();
+                               if (c1 == null || c2 == null)
+                                       // log.trace("undefined date");
+                                       ;
+                               lc = c1.getTimeInMillis() - c2.getTimeInMillis();
+                               if (lc < Integer.MIN_VALUE)
+                                       rc = -1;
+                               else if (lc > Integer.MAX_VALUE)
+                                       rc = 1;
+                               else
+                                       rc = (int) lc;
+                               break;
+                       case PropertyType.LONG:
+                               long l1;
+                               long l2;
+                               // TODO Sometimes an empty string is set instead of a long
+                               try {
+                                       l1 = v1.getLong();
+                               } catch (ValueFormatException ve) {
+                                       l1 = 0;
+                               }
+                               try {
+                                       l2 = v2.getLong();
+                               } catch (ValueFormatException ve) {
+                                       l2 = 0;
+                               }
+
+                               lc = l1 - l2;
+                               if (lc < Integer.MIN_VALUE)
+                                       rc = -1;
+                               else if (lc > Integer.MAX_VALUE)
+                                       rc = 1;
+                               else
+                                       rc = (int) lc;
+                               break;
+                       case PropertyType.DECIMAL:
+                               BigDecimal bd1 = v1.getDecimal();
+                               BigDecimal bd2 = v2.getDecimal();
+                               rc = bd1.compareTo(bd2);
+                               break;
+                       case PropertyType.DOUBLE:
+                               Double d1 = v1.getDouble();
+                               Double d2 = v2.getDouble();
+                               rc = d1.compareTo(d2);
+                               break;
+                       default:
+                               throw new EclipseUiException(
+                                               "Unimplemented comparaison for PropertyType "
+                                                               + propertyType);
+                       }
+                       // If descending order, flip the direction
+                       if (direction == DESCENDING) {
+                               rc = -rc;
+                       }
+
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Unexpected error "
+                                       + "while comparing nodes", re);
+               }
+               return rc;
+       }
+
+       /**
+        * @param propertyType
+        *            Corresponding JCR type
+        * @param propertyName
+        *            name of the property to use.
+        */
+       public void setColumn(int propertyType, String propertyName) {
+               if (this.propertyName != null && this.propertyName.equals(propertyName)) {
+                       // Same column as last sort; toggle the direction
+                       direction = 1 - direction;
+               } else {
+                       // New column; do an ascending sort
+                       this.propertyType = propertyType;
+                       this.propertyName = propertyName;
+                       direction = ASCENDING;
+               }
+       }
+
+       // Getters and setters
+       protected String getPropertyName() {
+               return propertyName;
+       }
+
+       protected void setPropertyName(String propertyName) {
+               this.propertyName = propertyName;
+       }
+
+       protected int getPropertyType() {
+               return propertyType;
+       }
+
+       protected void setPropertyType(int propertyType) {
+               this.propertyType = propertyType;
+       }
+
+       protected int getDirection() {
+               return direction;
+       }
+
+       protected void setDirection(int direction) {
+               this.direction = direction;
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/RowViewerComparator.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/RowViewerComparator.java
new file mode 100644 (file)
index 0000000..455fb0d
--- /dev/null
@@ -0,0 +1,62 @@
+package org.argeo.eclipse.ui.jcr.lists;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.query.Row;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * Base comparator to enable ordering on Table or Tree viewer that display Jcr
+ * rows
+ */
+public class RowViewerComparator extends NodeViewerComparator {
+       private static final long serialVersionUID = 7020939505172625113L;
+       protected String selectorName;
+
+       public RowViewerComparator() {
+       }
+
+       /**
+        * e1 and e2 must both be Jcr rows.
+        * 
+        * @param viewer
+        * @param e1
+        * @param e2
+        * @return
+        */
+       @Override
+       public int compare(Viewer viewer, Object e1, Object e2) {
+               try {
+                       Node n1 = ((Row) e1).getNode(selectorName);
+                       Node n2 = ((Row) e2).getNode(selectorName);
+                       return super.compare(viewer, n1, n2);
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Unexpected error "
+                                       + "while comparing nodes", re);
+               }
+       }
+
+       /**
+        * @param propertyType
+        *            Corresponding JCR type
+        * @param propertyName
+        *            name of the property to use.
+        */
+       public void setColumn(int propertyType, String selectorName,
+                       String propertyName) {
+               if (this.selectorName != null && getPropertyName() != null
+                               && this.selectorName.equals(selectorName)
+                               && this.getPropertyName().equals(propertyName)) {
+                       // Same column as last sort; toggle the direction
+                       setDirection(1 - getDirection());
+               } else {
+                       // New column; do a descending sort
+                       setPropertyType(propertyType);
+                       setPropertyName(propertyName);
+                       this.selectorName = selectorName;
+                       setDirection(NodeViewerComparator.ASCENDING);
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/SimpleJcrNodeLabelProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/SimpleJcrNodeLabelProvider.java
new file mode 100644 (file)
index 0000000..aa2e337
--- /dev/null
@@ -0,0 +1,120 @@
+package org.argeo.eclipse.ui.jcr.lists;
+
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+
+import javax.jcr.Node;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+
+/** Base implementation of a label provider for controls that display JCR Nodes */
+public class SimpleJcrNodeLabelProvider extends ColumnLabelProvider {
+       private static final long serialVersionUID = -5215787695436221993L;
+
+       private final static String DEFAULT_DATE_FORMAT = "EEE, dd MMM yyyy";
+       private final static String DEFAULT_NUMBER_FORMAT = "#,##0.0";
+
+       private DateFormat dateFormat;
+       private NumberFormat numberFormat;
+
+       final private String propertyName;
+
+       /**
+        * Default Label provider for a given property of a node. Using default
+        * pattern for date and number formating
+        */
+       public SimpleJcrNodeLabelProvider(String propertyName) {
+               this.propertyName = propertyName;
+               dateFormat = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
+               numberFormat = DecimalFormat.getInstance();
+               ((DecimalFormat) numberFormat).applyPattern(DEFAULT_NUMBER_FORMAT);
+       }
+
+       /**
+        * Label provider for a given property of a node optionally precising date
+        * and/or number format patterns
+        */
+       public SimpleJcrNodeLabelProvider(String propertyName,
+                       String dateFormatPattern, String numberFormatPattern) {
+               this.propertyName = propertyName;
+               dateFormat = new SimpleDateFormat(
+                               dateFormatPattern == null ? DEFAULT_DATE_FORMAT
+                                               : dateFormatPattern);
+               numberFormat = DecimalFormat.getInstance();
+               ((DecimalFormat) numberFormat)
+                               .applyPattern(numberFormatPattern == null ? DEFAULT_NUMBER_FORMAT
+                                               : numberFormatPattern);
+       }
+
+       @Override
+       public String getText(Object element) {
+               try {
+                       Node currNode = (Node) element;
+
+                       if (currNode.hasProperty(propertyName)) {
+                               if (currNode.getProperty(propertyName).isMultiple()) {
+                                       StringBuilder builder = new StringBuilder();
+                                       for (Value value : currNode.getProperty(propertyName)
+                                                       .getValues()) {
+                                               String currStr = getSingleValueAsString(value);
+                                               if (notEmptyString(currStr))
+                                                       builder.append(currStr).append("; ");
+                                       }
+                                       if (builder.length() > 0)
+                                               builder.deleteCharAt(builder.length() - 2);
+
+                                       return builder.toString();
+                               } else
+                                       return getSingleValueAsString(currNode.getProperty(
+                                                       propertyName).getValue());
+                       } else
+                               return "";
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Unable to get text from row", re);
+               }
+       }
+
+       private String getSingleValueAsString(Value value)
+                       throws RepositoryException {
+               switch (value.getType()) {
+               case PropertyType.STRING:
+                       return value.getString();
+               case PropertyType.BOOLEAN:
+                       return "" + value.getBoolean();
+               case PropertyType.DATE:
+                       return dateFormat.format(value.getDate().getTime());
+               case PropertyType.LONG:
+                       return "" + value.getLong();
+               case PropertyType.DECIMAL:
+                       return numberFormat.format(value.getDecimal());
+               case PropertyType.DOUBLE:
+                       return numberFormat.format(value.getDouble());
+               case PropertyType.NAME:
+                       return value.getString();
+               default:
+                       throw new EclipseUiException("Unimplemented label provider "
+                                       + "for property type " + value.getType()
+                                       + " while getting property " + propertyName + " - value: "
+                                       + value.getString());
+
+               }
+       }
+
+       private boolean notEmptyString(String string) {
+               return string != null && !"".equals(string.trim());
+       }
+
+       public void setDateFormat(String dateFormatPattern) {
+               dateFormat = new SimpleDateFormat(dateFormatPattern);
+       }
+
+       public void setNumberFormat(String numberFormatPattern) {
+               ((DecimalFormat) numberFormat).applyPattern(numberFormatPattern);
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/SimpleJcrRowLabelProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/SimpleJcrRowLabelProvider.java
new file mode 100644 (file)
index 0000000..5d421f6
--- /dev/null
@@ -0,0 +1,47 @@
+package org.argeo.eclipse.ui.jcr.lists;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.query.Row;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+
+/**
+ * Base implementation of a label provider for widgets that display JCR Rows.
+ */
+public class SimpleJcrRowLabelProvider extends SimpleJcrNodeLabelProvider {
+       private static final long serialVersionUID = -3414654948197181740L;
+
+       final private String selectorName;
+
+       /**
+        * Default Label provider for a given property of a row. Using default
+        * pattern for date and number formating
+        */
+       public SimpleJcrRowLabelProvider(String selectorName, String propertyName) {
+               super(propertyName);
+               this.selectorName = selectorName;
+       }
+
+       /**
+        * Label provider for a given property of a node optionally precising date
+        * and/or number format patterns
+        */
+       public SimpleJcrRowLabelProvider(String selectorName, String propertyName,
+                       String dateFormatPattern, String numberFormatPattern) {
+               super(propertyName, dateFormatPattern, numberFormatPattern);
+               this.selectorName = selectorName;
+       }
+
+       @Override
+       public String getText(Object element) {
+               try {
+                       Row currRow = (Row) element;
+                       Node currNode = currRow.getNode(selectorName);
+                       return super.getText(currNode);
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Unable to get Node " + selectorName
+                                       + " from row " + element, re);
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/package-info.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/lists/package-info.java
new file mode 100644 (file)
index 0000000..3678aab
--- /dev/null
@@ -0,0 +1,2 @@
+/** Generic SWT/JFace JCR utilities for lists. */
+package org.argeo.eclipse.ui.jcr.lists;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/package-info.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/package-info.java
new file mode 100644 (file)
index 0000000..19e3cc3
--- /dev/null
@@ -0,0 +1,2 @@
+/** Generic SWT/JFace JCR utilities. */
+package org.argeo.eclipse.ui.jcr;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/JcrFileProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/JcrFileProvider.java
new file mode 100644 (file)
index 0000000..c82e666
--- /dev/null
@@ -0,0 +1,129 @@
+package org.argeo.eclipse.ui.jcr.util;
+
+import java.io.InputStream;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.FileProvider;
+
+/**
+ * Implements a FileProvider for UI purposes. Note that it might not be very
+ * reliable as long as we have not fixed login and multi repository issues that
+ * will be addressed in the next version.
+ * 
+ * NOTE: id used here is the real id of the JCR Node, not the JCR Path
+ * 
+ * Relies on common approach for JCR file handling implementation.
+ * 
+ */
+@SuppressWarnings("deprecation")
+public class JcrFileProvider implements FileProvider {
+
+       // private Object[] rootNodes;
+       private Node refNode;
+
+       /**
+        * Must be set in order for the provider to be able to get current session
+        * and thus have the ability to get the file node corresponding to a given
+        * file ID
+        * 
+        * @param refNode
+        */
+       public void setReferenceNode(Node refNode) {
+               // FIXME : this introduces some concurrency ISSUES.
+               this.refNode = refNode;
+       }
+
+       public byte[] getByteArrayFileFromId(String fileId) {
+               InputStream fis = null;
+               byte[] ba = null;
+               Node child = getFileNodeFromId(fileId);
+               try {
+                       fis = (InputStream) child.getProperty(Property.JCR_DATA).getBinary().getStream();
+                       ba = IOUtils.toByteArray(fis);
+
+               } catch (Exception e) {
+                       throw new EclipseUiException("Stream error while opening file", e);
+               } finally {
+                       IOUtils.closeQuietly(fis);
+               }
+               return ba;
+       }
+
+       public InputStream getInputStreamFromFileId(String fileId) {
+               try {
+                       InputStream fis = null;
+
+                       Node child = getFileNodeFromId(fileId);
+                       fis = (InputStream) child.getProperty(Property.JCR_DATA).getBinary().getStream();
+                       return fis;
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Cannot get stream from file node for Id " + fileId, re);
+               }
+       }
+
+       /**
+        * Throws an exception if the node is not found in the current repository (a
+        * bit like a FileNotFoundException)
+        * 
+        * @param fileId
+        * @return Returns the child node of the nt:file node. It is the child node
+        *         that have the jcr:data property where actual file is stored.
+        *         never null
+        */
+       private Node getFileNodeFromId(String fileId) {
+               try {
+                       Node result = refNode.getSession().getNodeByIdentifier(fileId);
+
+                       // rootNodes: for (int j = 0; j < rootNodes.length; j++) {
+                       // // in case we have a classic JCR Node
+                       // if (rootNodes[j] instanceof Node) {
+                       // Node curNode = (Node) rootNodes[j];
+                       // if (result != null)
+                       // break rootNodes;
+                       // } // Case of a repository Node
+                       // else if (rootNodes[j] instanceof RepositoryNode) {
+                       // Object[] nodes = ((RepositoryNode) rootNodes[j])
+                       // .getChildren();
+                       // for (int i = 0; i < nodes.length; i++) {
+                       // Node node = (Node) nodes[i];
+                       // result = node.getSession().getNodeByIdentifier(fileId);
+                       // if (result != null)
+                       // break rootNodes;
+                       // }
+                       // }
+                       // }
+
+                       // Sanity checks
+                       if (result == null)
+                               throw new EclipseUiException("File node not found for ID" + fileId);
+
+                       Node child = null;
+
+                       boolean isValid = true;
+                       if (!result.isNodeType(NodeType.NT_FILE))
+                               // useless: mandatory child node
+                               // || !result.hasNode(Property.JCR_CONTENT))
+                               isValid = false;
+                       else {
+                               child = result.getNode(Property.JCR_CONTENT);
+                               if (!(child.isNodeType(NodeType.NT_RESOURCE) || child.hasProperty(Property.JCR_DATA)))
+                                       isValid = false;
+                       }
+
+                       if (!isValid)
+                               throw new EclipseUiException("ERROR: In the current implemented model, '" + NodeType.NT_FILE
+                                               + "' file node must have a child node named jcr:content "
+                                               + "that has a BINARY Property named jcr:data " + "where the actual data is stored");
+                       return child;
+
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Erreur while getting file node of ID " + fileId, re);
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/JcrItemsComparator.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/JcrItemsComparator.java
new file mode 100644 (file)
index 0000000..fb12399
--- /dev/null
@@ -0,0 +1,21 @@
+package org.argeo.eclipse.ui.jcr.util;
+
+import java.util.Comparator;
+
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+
+/** Compares two JCR items (node or properties) based on their names. */
+public class JcrItemsComparator implements Comparator<Item> {
+       public int compare(Item o1, Item o2) {
+               try {
+                       // TODO: put folder before files
+                       return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase());
+               } catch (RepositoryException e) {
+                       throw new EclipseUiException("Cannot compare " + o1 + " and " + o2, e);
+               }
+       }
+
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/NodeViewerComparer.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/NodeViewerComparer.java
new file mode 100644 (file)
index 0000000..54b795f
--- /dev/null
@@ -0,0 +1,36 @@
+package org.argeo.eclipse.ui.jcr.util;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.eclipse.jface.viewers.IElementComparer;
+
+/** Compare JCR nodes based on their JCR identifiers, for use in JFace viewers. */
+public class NodeViewerComparer implements IElementComparer {
+
+       // force comparison on Node IDs only.
+       public boolean equals(Object elementA, Object elementB) {
+               if (!(elementA instanceof Node) || !(elementB instanceof Node)) {
+                       return elementA == null ? elementB == null : elementA
+                                       .equals(elementB);
+               } else {
+
+                       boolean result = false;
+                       try {
+                               String idA = ((Node) elementA).getIdentifier();
+                               String idB = ((Node) elementB).getIdentifier();
+                               result = idA == null ? idB == null : idA.equals(idB);
+                       } catch (RepositoryException re) {
+                               throw new EclipseUiException("cannot compare nodes", re);
+                       }
+
+                       return result;
+               }
+       }
+
+       public int hashCode(Object element) {
+               // TODO enhanced this method.
+               return element.getClass().toString().hashCode();
+       }
+}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/SingleSessionFileProvider.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/SingleSessionFileProvider.java
new file mode 100644 (file)
index 0000000..291d579
--- /dev/null
@@ -0,0 +1,98 @@
+package org.argeo.eclipse.ui.jcr.util;
+
+import java.io.InputStream;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.eclipse.ui.EclipseUiException;
+import org.argeo.eclipse.ui.FileProvider;
+
+/**
+ * Implements a FileProvider for UI purposes. Unlike the
+ * <code> JcrFileProvider </code>, it relies on a single session and manages
+ * nodes with path only.
+ * 
+ * Note that considered id is the JCR path
+ * 
+ * Relies on common approach for JCR file handling implementation.
+ */
+@SuppressWarnings("deprecation")
+public class SingleSessionFileProvider implements FileProvider {
+
+       private Session session;
+
+       public SingleSessionFileProvider(Session session) {
+               this.session = session;
+       }
+
+       public byte[] getByteArrayFileFromId(String fileId) {
+               InputStream fis = null;
+               byte[] ba = null;
+               Node child = getFileNodeFromId(fileId);
+               try {
+                       fis = (InputStream) child.getProperty(Property.JCR_DATA)
+                                       .getBinary().getStream();
+                       ba = IOUtils.toByteArray(fis);
+
+               } catch (Exception e) {
+                       throw new EclipseUiException("Stream error while opening file", e);
+               } finally {
+                       IOUtils.closeQuietly(fis);
+               }
+               return ba;
+       }
+
+       public InputStream getInputStreamFromFileId(String fileId) {
+               try {
+                       InputStream fis = null;
+
+                       Node child = getFileNodeFromId(fileId);
+                       fis = (InputStream) child.getProperty(Property.JCR_DATA)
+                                       .getBinary().getStream();
+                       return fis;
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Cannot get stream from file node for Id "
+                                       + fileId, re);
+               }
+       }
+
+       /**
+        * 
+        * @param fileId
+        * @return Returns the child node of the nt:file node. It is the child node
+        *         that have the jcr:data property where actual file is stored.
+        *         never null
+        */
+       private Node getFileNodeFromId(String fileId) {
+               try {
+                       Node result = null;
+                       result = session.getNode(fileId);
+
+                       // Sanity checks
+                       if (result == null)
+                               throw new EclipseUiException("File node not found for ID" + fileId);
+
+                       // Ensure that the node have the correct type.
+                       if (!result.isNodeType(NodeType.NT_FILE))
+                               throw new EclipseUiException(
+                                               "Cannot open file children Node that are not of "
+                                                               + NodeType.NT_RESOURCE + " type.");
+
+                       Node child = result.getNodes().nextNode();
+                       if (child == null || !child.isNodeType(NodeType.NT_RESOURCE))
+                               throw new EclipseUiException(
+                                               "ERROR: IN the current implemented model, "
+                                                               + NodeType.NT_FILE
+                                                               + "  file node must have one and only one child of the nt:ressource, where actual data is stored");
+                       return child;
+               } catch (RepositoryException re) {
+                       throw new EclipseUiException("Erreur while getting file node of ID "
+                                       + fileId, re);
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/package-info.java b/jcr/org.argeo.cms.jcr.ui/src/org/argeo/eclipse/ui/jcr/util/package-info.java
new file mode 100644 (file)
index 0000000..016348c
--- /dev/null
@@ -0,0 +1,2 @@
+/** Generic SWT/JFace JCR helpers. */
+package org.argeo.eclipse.ui.jcr.util;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/.classpath b/jcr/org.argeo.cms.ui/.classpath
deleted file mode 100644 (file)
index 81fe078..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
-       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-       <classpathentry kind="src" path="src"/>
-       <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/jcr/org.argeo.cms.ui/.project b/jcr/org.argeo.cms.ui/.project
deleted file mode 100644 (file)
index e52eb8e..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.cms.ui</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.jdt.core.javabuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.ManifestBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.SchemaBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.pde.PluginNature</nature>
-               <nature>org.eclipse.jdt.core.javanature</nature>
-       </natures>
-</projectDescription>
diff --git a/jcr/org.argeo.cms.ui/META-INF/.gitignore b/jcr/org.argeo.cms.ui/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/jcr/org.argeo.cms.ui/bnd.bnd b/jcr/org.argeo.cms.ui/bnd.bnd
deleted file mode 100644 (file)
index c3c609c..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-Bundle-Activator: org.argeo.cms.ui.internal.Activator
-Bundle-ActivationPolicy: lazy
-
-Import-Package: org.eclipse.swt,\
-org.eclipse.jface.window,\
-org.eclipse.core.commands,\
-javax.jcr.security,\
-org.eclipse.rap.fileupload;version="[2.1,4)",\
-org.eclipse.rap.rwt;version="[2.1,4)",\
-org.eclipse.rap.rwt.application;version="[2.1,4)",\
-org.eclipse.rap.rwt.client;version="[2.1,4)",\
-org.eclipse.rap.rwt.client.service;version="[2.1,4)",\
-org.eclipse.rap.rwt.service;version="[2.1,4)",\
-org.eclipse.rap.rwt.widgets;version="[2.1,4)",\
-org.osgi.*;version=0.0.0,\
-javax.servlet.*;version="[3,5)",\
-*
-
-## TODO: in order to enable single sourcing, we have introduced dummy RAP packages 
-# in the RCP specific bundle org.argeo.eclipse.ui.rap.
-# this was working with RAP 2.x but since we upgrade Rap to 3.1.x, 
-# there is a version range issue cause org.argeo.eclipse.ui.rap bundle is still in 2.x
-# We enable large RAP version range as a workaround that must be fixed 
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/build.properties b/jcr/org.argeo.cms.ui/build.properties
deleted file mode 100644 (file)
index c6baffa..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               .,\
-               icons/
diff --git a/jcr/org.argeo.cms.ui/icons/loading.gif b/jcr/org.argeo.cms.ui/icons/loading.gif
deleted file mode 100644 (file)
index 3288d10..0000000
Binary files a/jcr/org.argeo.cms.ui/icons/loading.gif and /dev/null differ
diff --git a/jcr/org.argeo.cms.ui/icons/noPic-goldenRatio-640px.png b/jcr/org.argeo.cms.ui/icons/noPic-goldenRatio-640px.png
deleted file mode 100644 (file)
index 0396506..0000000
Binary files a/jcr/org.argeo.cms.ui/icons/noPic-goldenRatio-640px.png and /dev/null differ
diff --git a/jcr/org.argeo.cms.ui/icons/noPic-square-640px.png b/jcr/org.argeo.cms.ui/icons/noPic-square-640px.png
deleted file mode 100644 (file)
index 8e3abb5..0000000
Binary files a/jcr/org.argeo.cms.ui/icons/noPic-square-640px.png and /dev/null differ
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiConstants.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiConstants.java
deleted file mode 100644 (file)
index c6a62e9..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.argeo.cms.ui;
-
-import org.argeo.api.cms.ux.Cms2DSize;
-
-/** Commons constants */
-@Deprecated
-public interface CmsUiConstants {
-       // DATAKEYS
-//     public final static String STYLE = EclipseUiConstants.CSS_CLASS;
-//     public final static String MARKUP = EclipseUiConstants.MARKUP_SUPPORT;
-       @Deprecated
-       /* RWT.CUSTOM_ITEM_HEIGHT */
-       public final static String ITEM_HEIGHT = "org.eclipse.rap.rwt.customItemHeight";
-
-       // EVENT DETAILS
-       @Deprecated
-       /* RWT.HYPERLINK */
-       public final static int HYPERLINK = 1 << 26;
-
-       // STANDARD RESOURCES
-       public final static String LOADING_IMAGE = "icons/loading.gif";
-
-       public final static String NO_IMAGE = "icons/noPic-square-640px.png";
-       public final static Cms2DSize NO_IMAGE_SIZE = new Cms2DSize(320, 320);
-       public final static Float NO_IMAGE_RATIO = 1f;
-       // MISCEALLENEOUS
-       String DATE_TIME_FORMAT = "dd/MM/yyyy, HH:mm";
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java
deleted file mode 100644 (file)
index 5f2377b..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.argeo.cms.ui;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.acr.Content;
-import org.argeo.cms.jcr.acr.JcrContent;
-import org.argeo.cms.swt.acr.SwtUiProvider;
-import org.argeo.jcr.JcrException;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Stateless factory building an SWT user interface given a JCR context. */
-public interface CmsUiProvider extends SwtUiProvider {
-       /**
-        * Initialises a user interface.
-        * 
-        * @param parent  the parent composite
-        * @param context a context node (holding the JCR underlying session), or null
-        */
-       default Control createUi(Composite parent, Node context) throws RepositoryException {
-               // does nothing by default
-               return null;
-       }
-
-       default Control createUiPart(Composite parent, Node context) {
-               try {
-                       return createUi(parent, context);
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot create UI for context " + context, e);
-               }
-       }
-
-       @Override
-       default Control createUiPart(Composite parent, Content context) {
-               if (context == null)
-                       return createUiPart(parent, (Node) null);
-               if (context instanceof JcrContent) {
-                       Node node = ((JcrContent) context).getJcrNode();
-                       return createUiPart(parent, node);
-               } else {
-//                     CmsLog.getLog(CmsUiProvider.class)
-//                                     .warn("In " + getClass() + ", content " + context + " is not compatible with JCR.");
-//                     return createUiPart(parent, (Node) null);
-
-                       throw new IllegalArgumentException(
-                                       "In " + getClass() + ", content " + context + " is not compatible with JCR");
-               }
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/LifeCycleUiProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/LifeCycleUiProvider.java
deleted file mode 100644 (file)
index 5d77c15..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.argeo.cms.ui;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-/** CmsUiProvider notified of initialisation with a system session. */
-public interface LifeCycleUiProvider extends CmsUiProvider {
-       public void init(Session adminSession) throws RepositoryException;
-
-       public void destroy();
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/AbstractFormPart.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/AbstractFormPart.java
deleted file mode 100644 (file)
index 4ce4688..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms;
-/**
- * AbstractFormPart implements IFormPart interface and can be used as a
- * convenient base class for concrete form parts. If a method contains
- * code that must be called, look for instructions to call 'super'
- * when overriding.
- * 
- * @see org.eclipse.ui.forms.widgets.Section
- * @since 1.0
- */
-public abstract class AbstractFormPart implements IFormPart {
-       private IManagedForm managedForm;
-       private boolean dirty = false;
-       private boolean stale = true;
-       /**
-        * @see org.eclipse.ui.forms.IFormPart#initialize(org.eclipse.ui.forms.IManagedForm)
-        */
-       public void initialize(IManagedForm form) {
-               this.managedForm = form;
-       }
-       /**
-        * Returns the form that manages this part.
-        * 
-        * @return the managed form
-        */
-       public IManagedForm getManagedForm() {
-               return managedForm;
-       }
-       /**
-        * Disposes the part. Subclasses should override to release any system
-        * resources.
-        */
-       public void dispose() {
-       }
-       /**
-        * Commits the part. Subclasses should call 'super' when overriding.
-        * 
-        * @param onSave
-        *            <code>true</code> if the request to commit has arrived as a
-        *            result of the 'save' action.
-        */
-       public void commit(boolean onSave) {
-               dirty = false;
-       }
-       /**
-        * Sets the overall form input. Subclases may elect to override the method
-        * and adjust according to the form input.
-        * 
-        * @param input
-        *            the form input object
-        * @return <code>false</code>
-        */
-       public boolean setFormInput(Object input) {
-               return false;
-       }
-       /**
-        * Instructs the part to grab keyboard focus.
-        */
-       public void setFocus() {
-       }
-       /**
-        * Refreshes the section after becoming stale (falling behind data in the
-        * model). Subclasses must call 'super' when overriding this method.
-        */
-       public void refresh() {
-               stale = false;
-               // since we have refreshed, any changes we had in the
-               // part are gone and we are not dirty
-               dirty = false;
-       }
-       /**
-        * Marks the part dirty. Subclasses should call this method as a result of
-        * user interaction with the widgets in the section.
-        */
-       public void markDirty() {
-               dirty = true;
-               managedForm.dirtyStateChanged();
-       }
-       /**
-        * Tests whether the part is dirty i.e. its widgets have state that is
-        * newer than the data in the model.
-        * 
-        * @return <code>true</code> if the part is dirty, <code>false</code>
-        *         otherwise.
-        */
-       public boolean isDirty() {
-               return dirty;
-       }
-       /**
-        * Tests whether the part is stale i.e. its widgets have state that is
-        * older than the data in the model.
-        * 
-        * @return <code>true</code> if the part is stale, <code>false</code>
-        *         otherwise.
-        */
-       public boolean isStale() {
-               return stale;
-       }
-       /**
-        * Marks the part stale. Subclasses should call this method as a result of
-        * model notification that indicates that the content of the section is no
-        * longer in sync with the model.
-        */
-       public void markStale() {
-               stale = true;
-               managedForm.staleStateChanged();
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/FormColors.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/FormColors.java
deleted file mode 100644 (file)
index 32b031b..0000000
+++ /dev/null
@@ -1,730 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.eclipse.jface.resource.JFaceResources;
-import org.eclipse.jface.resource.LocalResourceManager;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.RGB;
-//import org.eclipse.swt.internal.graphics.Graphics;
-import org.eclipse.swt.widgets.Display;
-
-/**
- * Manages colors that will be applied to forms and form widgets. The colors are
- * chosen to make the widgets look correct in the editor area. If a different
- * set of colors is needed, subclass this class and override 'initialize' and/or
- * 'initializeColors'.
- * 
- * @since 1.0
- */
-public class FormColors {
-       /**
-        * Key for the form title foreground color.
-        * 
-        * @deprecated use <code>IFormColors.TITLE</code>.
-        */
-       public static final String TITLE = IFormColors.TITLE;
-
-       /**
-        * Key for the tree/table border color.
-        * 
-        * @deprecated use <code>IFormColors.BORDER</code>
-        */
-       public static final String BORDER = IFormColors.BORDER;
-
-       /**
-        * Key for the section separator color.
-        * 
-        * @deprecated use <code>IFormColors.SEPARATOR</code>.
-        */
-       public static final String SEPARATOR = IFormColors.SEPARATOR;
-
-       /**
-        * Key for the section title bar background.
-        * 
-        * @deprecated use <code>IFormColors.TB_BG
-        */
-       public static final String TB_BG = IFormColors.TB_BG;
-
-       /**
-        * Key for the section title bar foreground.
-        * 
-        * @deprecated use <code>IFormColors.TB_FG</code>
-        */
-       public static final String TB_FG = IFormColors.TB_FG;
-
-       /**
-        * Key for the section title bar gradient.
-        * 
-        * @deprecated use <code>IFormColors.TB_GBG</code>
-        */
-       public static final String TB_GBG = IFormColors.TB_GBG;
-
-       /**
-        * Key for the section title bar border.
-        * 
-        * @deprecated use <code>IFormColors.TB_BORDER</code>.
-        */
-       public static final String TB_BORDER = IFormColors.TB_BORDER;
-
-       /**
-        * Key for the section toggle color. Since 3.1, this color is used for all
-        * section styles.
-        * 
-        * @deprecated use <code>IFormColors.TB_TOGGLE</code>.
-        */
-       public static final String TB_TOGGLE = IFormColors.TB_TOGGLE;
-
-       /**
-        * Key for the section toggle hover color.
-        * 
-        * @deprecated use <code>IFormColors.TB_TOGGLE_HOVER</code>.
-        */
-       public static final String TB_TOGGLE_HOVER = IFormColors.TB_TOGGLE_HOVER;
-
-       protected Map colorRegistry = new HashMap(10);
-
-       private LocalResourceManager resources;
-
-       protected Color background;
-
-       protected Color foreground;
-
-       private boolean shared;
-
-       protected Display display;
-
-       protected Color border;
-
-       /**
-        * Creates form colors using the provided display.
-        * 
-        * @param display
-        *            the display to use
-        */
-       public FormColors(Display display) {
-               this.display = display;
-               initialize();
-       }
-
-       /**
-        * Returns the display used to create colors.
-        * 
-        * @return the display
-        */
-       public Display getDisplay() {
-               return display;
-       }
-
-       /**
-        * Initializes the colors. Subclasses can override this method to change the
-        * way colors are created. Alternatively, only the color table can be
-        * modified by overriding <code>initializeColorTable()</code>.
-        * 
-        * @see #initializeColorTable
-        */
-       protected void initialize() {
-               background = display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
-               foreground = display.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
-               initializeColorTable();
-               updateBorderColor();
-       }
-
-       /**
-        * Allocates colors for the following keys: BORDER, SEPARATOR and
-        * TITLE. Subclasses can override to allocate these colors differently.
-        */
-       protected void initializeColorTable() {
-               createTitleColor();
-               createColor(IFormColors.SEPARATOR, getColor(IFormColors.TITLE).getRGB());
-               RGB black = getSystemColor(SWT.COLOR_BLACK);
-               RGB borderRGB = getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT);
-               createColor(IFormColors.BORDER, blend(borderRGB, black, 80));
-       }
-
-       /**
-        * Allocates colors for the section tool bar (all the keys that start with
-        * TB). Since these colors are only needed when TITLE_BAR style is used with
-        * the Section widget, they are not needed all the time and are allocated on
-        * demand. Consequently, this method will do nothing if the colors have been
-        * already initialized. Call this method prior to using colors with the TB
-        * keys to ensure they are available.
-        */
-       public void initializeSectionToolBarColors() {
-               if (colorRegistry.containsKey(IFormColors.TB_BG))
-                       return;
-               createTitleBarGradientColors();
-               createTitleBarOutlineColors();
-               createTwistieColors();
-       }
-
-       /**
-        * Allocates additional colors for the form header, namely background
-        * gradients, bottom separator keylines and DND highlights. Since these
-        * colors are only needed for clients that want to use these particular
-        * style of header rendering, they are not needed all the time and are
-        * allocated on demand. Consequently, this method will do nothing if the
-        * colors have been already initialized. Call this method prior to using
-        * color keys with the H_ prefix to ensure they are available.
-        */
-       protected void initializeFormHeaderColors() {
-               if (colorRegistry.containsKey(IFormColors.H_BOTTOM_KEYLINE2))
-                       return;
-               createFormHeaderColors();
-       }
-
-       /**
-        * Returns the RGB value of the system color represented by the code
-        * argument, as defined in <code>SWT</code> class.
-        * 
-        * @param code
-        *            the system color constant as defined in <code>SWT</code>
-        *            class.
-        * @return the RGB value of the system color
-        */
-       public RGB getSystemColor(int code) {
-               return getDisplay().getSystemColor(code).getRGB();
-       }
-
-       /**
-        * Creates the color for the specified key using the provided RGB object.
-        * The color object will be returned and also put into the registry. When
-        * the class is disposed, the color will be disposed with it.
-        * 
-        * @param key
-        *            the unique color key
-        * @param rgb
-        *            the RGB object
-        * @return the allocated color object
-        */
-       public Color createColor(String key, RGB rgb) {
-               // RAP [rh] changes due to missing Color constructor
-//             Color c = getResourceManager().createColor(rgb);
-//             Color prevC = (Color) colorRegistry.get(key);
-//             if (prevC != null && !prevC.isDisposed())
-//                     getResourceManager().destroyColor(prevC.getRGB());
-//             Color c = Graphics.getColor(rgb);
-               Color c = new Color(display, rgb);
-               colorRegistry.put(key, c);        
-               return c;
-       }
-
-       /**
-        * Creates a color that can be used for areas of the form that is inactive.
-        * These areas can contain images, links, controls and other content but are
-        * considered auxilliary to the main content area.
-        * 
-        * <p>
-        * The color should not be disposed because it is managed by this class.
-        * 
-        * @return the inactive form color
-        */
-       public Color getInactiveBackground() {
-               String key = "__ncbg__"; //$NON-NLS-1$
-               Color color = getColor(key);
-               if (color == null) {
-                       RGB sel = getSystemColor(SWT.COLOR_LIST_SELECTION);
-                       // a blend of 95% white and 5% list selection system color
-                       RGB ncbg = blend(sel, getSystemColor(SWT.COLOR_WHITE), 5);
-                       color = createColor(key, ncbg);
-               }
-               return color;
-       }
-
-       /**
-        * Creates the color for the specified key using the provided RGB values.
-        * The color object will be returned and also put into the registry. If
-        * there is already another color object under the same key in the registry,
-        * the existing object will be disposed. When the class is disposed, the
-        * color will be disposed with it.
-        * 
-        * @param key
-        *            the unique color key
-        * @param r
-        *            red value
-        * @param g
-        *            green value
-        * @param b
-        *            blue value
-        * @return the allocated color object
-        */
-       public Color createColor(String key, int r, int g, int b) {
-               return createColor(key, new RGB(r,g,b));
-       }
-
-       /**
-        * Computes the border color relative to the background. Allocated border
-        * color is designed to work well with white. Otherwise, stanard widget
-        * background color will be used.
-        */
-       protected void updateBorderColor() {
-               if (isWhiteBackground())
-                       border = getColor(IFormColors.BORDER);
-               else {
-                       border = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
-                       Color bg = getImpliedBackground();
-                       if (border.getRed() == bg.getRed()
-                                       && border.getGreen() == bg.getGreen()
-                                       && border.getBlue() == bg.getBlue())
-                               border = display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW);
-               }
-       }
-
-       /**
-        * Sets the background color. All the toolkits that use this class will
-        * share the same background.
-        * 
-        * @param bg
-        *            background color
-        */
-       public void setBackground(Color bg) {
-               this.background = bg;
-               updateBorderColor();
-               updateFormHeaderColors();
-       }
-
-       /**
-        * Sets the foreground color. All the toolkits that use this class will
-        * share the same foreground.
-        * 
-        * @param fg
-        *            foreground color
-        */
-       public void setForeground(Color fg) {
-               this.foreground = fg;
-       }
-
-       /**
-        * Returns the current background color.
-        * 
-        * @return the background color
-        */
-       public Color getBackground() {
-               return background;
-       }
-
-       /**
-        * Returns the current foreground color.
-        * 
-        * @return the foreground color
-        */
-       public Color getForeground() {
-               return foreground;
-       }
-
-       /**
-        * Returns the computed border color. Border color depends on the background
-        * and is recomputed whenever the background changes.
-        * 
-        * @return the current border color
-        */
-       public Color getBorderColor() {
-               return border;
-       }
-
-       /**
-        * Tests if the background is white. White background has RGB value
-        * 255,255,255.
-        * 
-        * @return <samp>true</samp> if background is white, <samp>false</samp>
-        *         otherwise.
-        */
-       public boolean isWhiteBackground() {
-               Color bg = getImpliedBackground();
-               return bg.getRed() == 255 && bg.getGreen() == 255
-                               && bg.getBlue() == 255;
-       }
-
-       /**
-        * Returns the color object for the provided key or <samp>null </samp> if
-        * not in the registry.
-        * 
-        * @param key
-        *            the color key
-        * @return color object if found, or <samp>null </samp> if not.
-        */
-       public Color getColor(String key) {
-               if (key.startsWith(IFormColors.TB_PREFIX))
-                       initializeSectionToolBarColors();
-               else if (key.startsWith(IFormColors.H_PREFIX))
-                       initializeFormHeaderColors();
-               return (Color) colorRegistry.get(key);
-       }
-
-       /**
-        * Disposes all the colors in the registry.
-        */
-       public void dispose() {
-               if (resources != null)
-                       resources.dispose();
-               resources = null;
-               colorRegistry = null;
-       }
-
-       /**
-        * Marks the colors shared. This prevents toolkits that share this object
-        * from disposing it.
-        */
-       public void markShared() {
-               this.shared = true;
-       }
-
-       /**
-        * Tests if the colors are shared.
-        * 
-        * @return <code>true</code> if shared, <code>false</code> otherwise.
-        */
-       public boolean isShared() {
-               return shared;
-       }
-
-       /**
-        * Blends c1 and c2 based in the provided ratio.
-        * 
-        * @param c1
-        *            first color
-        * @param c2
-        *            second color
-        * @param ratio
-        *            percentage of the first color in the blend (0-100)
-        * @return the RGB value of the blended color
-        */
-       public static RGB blend(RGB c1, RGB c2, int ratio) {
-               int r = blend(c1.red, c2.red, ratio);
-               int g = blend(c1.green, c2.green, ratio);
-               int b = blend(c1.blue, c2.blue, ratio);
-               return new RGB(r, g, b);
-       }
-
-       /**
-        * Tests the source RGB for range.
-        * 
-        * @param rgb
-        *            the tested RGB
-        * @param from
-        *            range start (excluding the value itself)
-        * @param to
-        *            range end (excluding the value itself)
-        * @return <code>true</code> if at least one of the primary colors in the
-        *         source RGB are within the provided range, <code>false</code>
-        *         otherwise.
-        */
-       public static boolean testAnyPrimaryColor(RGB rgb, int from, int to) {
-               if (testPrimaryColor(rgb.red, from, to))
-                       return true;
-               if (testPrimaryColor(rgb.green, from, to))
-                       return true;
-               if (testPrimaryColor(rgb.blue, from, to))
-                       return true;
-               return false;
-       }
-
-       /**
-        * Tests the source RGB for range.
-        * 
-        * @param rgb
-        *            the tested RGB
-        * @param from
-        *            range start (excluding the value itself)
-        * @param to
-        *            tange end (excluding the value itself)
-        * @return <code>true</code> if at least two of the primary colors in the
-        *         source RGB are within the provided range, <code>false</code>
-        *         otherwise.
-        */
-       public static boolean testTwoPrimaryColors(RGB rgb, int from, int to) {
-               int total = 0;
-               if (testPrimaryColor(rgb.red, from, to))
-                       total++;
-               if (testPrimaryColor(rgb.green, from, to))
-                       total++;
-               if (testPrimaryColor(rgb.blue, from, to))
-                       total++;
-               return total >= 2;
-       }
-
-       /**
-        * Blends two primary color components based on the provided ratio.
-        * 
-        * @param v1
-        *            first component
-        * @param v2
-        *            second component
-        * @param ratio
-        *            percentage of the first component in the blend
-        * @return
-        */
-       private static int blend(int v1, int v2, int ratio) {
-               int b = (ratio * v1 + (100 - ratio) * v2) / 100;
-               return Math.min(255, b);
-       }
-
-       private Color getImpliedBackground() {
-               if (getBackground() != null)
-                       return getBackground();
-               return getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
-       }
-
-       private static boolean testPrimaryColor(int value, int from, int to) {
-               return value > from && value < to;
-       }
-
-       private void createTitleColor() {
-               /*
-                * RGB rgb = getSystemColor(SWT.COLOR_LIST_SELECTION); // test too light
-                * if (testTwoPrimaryColors(rgb, 120, 151)) rgb = blend(rgb, BLACK, 80);
-                * else if (testTwoPrimaryColors(rgb, 150, 256)) rgb = blend(rgb, BLACK,
-                * 50); createColor(TITLE, rgb);
-                */
-               RGB bg = getImpliedBackground().getRGB();
-               RGB listSelection = getSystemColor(SWT.COLOR_LIST_SELECTION);
-               RGB listForeground = getSystemColor(SWT.COLOR_LIST_FOREGROUND);
-               RGB rgb = listSelection;
-
-               // Group 1
-               // Rule: If at least 2 of the LIST_SELECTION RGB values are equal to or
-               // between 0 and 120, then use 100% LIST_SELECTION as it is (no
-               // additions)
-               // Examples: XP Default, Win Classic Standard, Win High Con White, Win
-               // Classic Marine
-               if (testTwoPrimaryColors(listSelection, -1, 121))
-                       rgb = listSelection;
-               // Group 2
-               // When LIST_BACKGROUND = white (255, 255, 255) or not black, text
-               // colour = LIST_SELECTION @ 100% Opacity + 50% LIST_FOREGROUND over
-               // LIST_BACKGROUND
-               // Rule: If at least 2 of the LIST_SELECTION RGB values are equal to or
-               // between 121 and 255, then add 50% LIST_FOREGROUND to LIST_SELECTION
-               // foreground colour
-               // Examples: Win Vista, XP Silver, XP Olive , Win Classic Plum, OSX
-               // Aqua, OSX Graphite, Linux GTK
-               else if (testTwoPrimaryColors(listSelection, 120, 256)
-                               || (bg.red == 0 && bg.green == 0 && bg.blue == 0))
-                       rgb = blend(listSelection, listForeground, 50);
-               // Group 3
-               // When LIST_BACKGROUND = black (0, 0, 0), text colour = LIST_SELECTION
-               // @ 100% Opacity + 50% LIST_FOREGROUND over LIST_BACKGROUND
-               // Rule: If LIST_BACKGROUND = 0, 0, 0, then add 50% LIST_FOREGROUND to
-               // LIST_SELECTION foreground colour
-               // Examples: Win High Con Black, Win High Con #1, Win High Con #2
-               // (covered in the second part of the OR clause above)
-               createColor(IFormColors.TITLE, rgb);
-       }
-
-       private void createTwistieColors() {
-               RGB rgb = getColor(IFormColors.TITLE).getRGB();
-               RGB white = getSystemColor(SWT.COLOR_WHITE);
-               createColor(TB_TOGGLE, rgb);
-               rgb = blend(rgb, white, 60);
-               createColor(TB_TOGGLE_HOVER, rgb);
-       }
-
-       private void createTitleBarGradientColors() {
-               RGB tbBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
-               RGB bg = getImpliedBackground().getRGB();
-
-               // Group 1
-               // Rule: If at least 2 of the RGB values are equal to or between 180 and
-               // 255, then apply specified opacity for Group 1
-               // Examples: Vista, XP Silver, Wn High Con #2
-               // Gradient Bottom = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
-               // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
-               if (testTwoPrimaryColors(tbBg, 179, 256))
-                       tbBg = blend(tbBg, bg, 30);
-
-               // Group 2
-               // Rule: If at least 2 of the RGB values are equal to or between 121 and
-               // 179, then apply specified opacity for Group 2
-               // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
-               // Gradient Bottom = TITLE_BACKGROUND @ 20% Opacity over LIST_BACKGROUND
-               // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
-               else if (testTwoPrimaryColors(tbBg, 120, 180))
-                       tbBg = blend(tbBg, bg, 20);
-
-               // Group 3
-               // Rule: Everything else
-               // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
-               // Aqua, Wn High Con White, Wn High Con #1
-               // Gradient Bottom = TITLE_BACKGROUND @ 10% Opacity over LIST_BACKGROUND
-               // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
-               else {
-                       tbBg = blend(tbBg, bg, 10);
-               }
-
-               createColor(IFormColors.TB_BG, tbBg);
-               
-               // for backward compatibility
-               createColor(TB_GBG, tbBg);
-       }
-
-       private void createTitleBarOutlineColors() {
-               // title bar outline - border color
-               RGB tbBorder = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
-               RGB bg = getImpliedBackground().getRGB();
-               // Group 1
-               // Rule: If at least 2 of the RGB values are equal to or between 180 and
-               // 255, then apply specified opacity for Group 1
-               // Examples: Vista, XP Silver, Wn High Con #2
-               // Keyline = TITLE_BACKGROUND @ 70% Opacity over LIST_BACKGROUND
-               if (testTwoPrimaryColors(tbBorder, 179, 256))
-                       tbBorder = blend(tbBorder, bg, 70);
-
-               // Group 2
-               // Rule: If at least 2 of the RGB values are equal to or between 121 and
-               // 179, then apply specified opacity for Group 2
-               // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
-
-               // Keyline = TITLE_BACKGROUND @ 50% Opacity over LIST_BACKGROUND
-               else if (testTwoPrimaryColors(tbBorder, 120, 180))
-                       tbBorder = blend(tbBorder, bg, 50);
-
-               // Group 3
-               // Rule: Everything else
-               // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
-               // Aqua, Wn High Con White, Wn High Con #1
-
-               // Keyline = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
-               else {
-                       tbBorder = blend(tbBorder, bg, 30);
-               }
-               createColor(FormColors.TB_BORDER, tbBorder);
-       }
-
-       private void updateFormHeaderColors() {
-               if (colorRegistry.containsKey(IFormColors.H_GRADIENT_END)) {
-                       disposeIfFound(IFormColors.H_GRADIENT_END);
-                       disposeIfFound(IFormColors.H_GRADIENT_START);
-                       disposeIfFound(IFormColors.H_BOTTOM_KEYLINE1);
-                       disposeIfFound(IFormColors.H_BOTTOM_KEYLINE2);
-                       disposeIfFound(IFormColors.H_HOVER_LIGHT);
-                       disposeIfFound(IFormColors.H_HOVER_FULL);
-                       initializeFormHeaderColors();
-               }
-       }
-
-       private void disposeIfFound(String key) {
-               Color color = getColor(key);
-               if (color != null) {
-                       colorRegistry.remove(key);
-               // RAP [rh] changes due to missing Color#dispose()                      
-//                     color.dispose();
-               }
-       }
-
-       private void createFormHeaderColors() {
-               createFormHeaderGradientColors();
-               createFormHeaderKeylineColors();
-               createFormHeaderDNDColors();
-       }
-
-       private void createFormHeaderGradientColors() {
-               RGB titleBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
-               Color bgColor = getImpliedBackground();
-               RGB bg = bgColor.getRGB();
-               RGB bottom, top;
-               // Group 1
-               // Rule: If at least 2 of the RGB values are equal to or between 180 and
-               // 255, then apply specified opacity for Group 1
-               // Examples: Vista, XP Silver, Wn High Con #2
-               // Gradient Bottom = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
-               // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
-               if (testTwoPrimaryColors(titleBg, 179, 256)) {
-                       bottom = blend(titleBg, bg, 30);
-                       top = bg;
-               }
-
-               // Group 2
-               // Rule: If at least 2 of the RGB values are equal to or between 121 and
-               // 179, then apply specified opacity for Group 2
-               // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
-               // Gradient Bottom = TITLE_BACKGROUND @ 20% Opacity over LIST_BACKGROUND
-               // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
-               else if (testTwoPrimaryColors(titleBg, 120, 180)) {
-                       bottom = blend(titleBg, bg, 20);
-                       top = bg;
-               }
-
-               // Group 3
-               // Rule: If at least 2 of the RGB values are equal to or between 0 and
-               // 120, then apply specified opacity for Group 3
-               // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
-               // Aqua, Wn High Con White, Wn High Con #1
-               // Gradient Bottom = TITLE_BACKGROUND @ 10% Opacity over LIST_BACKGROUND
-               // Gradient Top = TITLE BACKGROUND @ 0% Opacity over LIST_BACKGROUND
-               else {
-                       bottom = blend(titleBg, bg, 10);
-                       top = bg;
-               }
-               createColor(IFormColors.H_GRADIENT_END, top);
-               createColor(IFormColors.H_GRADIENT_START, bottom);
-       }
-
-       private void createFormHeaderKeylineColors() {
-               RGB titleBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND);
-               Color bgColor = getImpliedBackground();
-               RGB bg = bgColor.getRGB();
-               RGB keyline2;
-               // H_BOTTOM_KEYLINE1
-               createColor(IFormColors.H_BOTTOM_KEYLINE1, new RGB(255, 255, 255));
-
-               // H_BOTTOM_KEYLINE2
-               // Group 1
-               // Rule: If at least 2 of the RGB values are equal to or between 180 and
-               // 255, then apply specified opacity for Group 1
-               // Examples: Vista, XP Silver, Wn High Con #2
-               // Keyline = TITLE_BACKGROUND @ 70% Opacity over LIST_BACKGROUND
-               if (testTwoPrimaryColors(titleBg, 179, 256))
-                       keyline2 = blend(titleBg, bg, 70);
-
-               // Group 2
-               // Rule: If at least 2 of the RGB values are equal to or between 121 and
-               // 179, then apply specified opacity for Group 2
-               // Examples: XP Olive, OSX Graphite, Linux GTK, Wn High Con Black
-               // Keyline = TITLE_BACKGROUND @ 50% Opacity over LIST_BACKGROUND
-               else if (testTwoPrimaryColors(titleBg, 120, 180))
-                       keyline2 = blend(titleBg, bg, 50);
-
-               // Group 3
-               // Rule: If at least 2 of the RGB values are equal to or between 0 and
-               // 120, then apply specified opacity for Group 3
-               // Examples: XP Default, Wn Classic Standard, Wn Marine, Wn Plum, OSX
-               // Aqua, Wn High Con White, Wn High Con #1
-
-               // Keyline = TITLE_BACKGROUND @ 30% Opacity over LIST_BACKGROUND
-               else
-                       keyline2 = blend(titleBg, bg, 30);
-               // H_BOTTOM_KEYLINE2
-               createColor(IFormColors.H_BOTTOM_KEYLINE2, keyline2);
-       }
-
-       private void createFormHeaderDNDColors() {
-               RGB titleBg = getSystemColor(SWT.COLOR_TITLE_BACKGROUND_GRADIENT);
-               Color bgColor = getImpliedBackground();
-               RGB bg = bgColor.getRGB();
-               RGB light, full;
-               // ALL Themes
-               //
-               // Light Highlight
-               // When *near* the 'hot' area
-               // Rule: If near the title in the 'hot' area, show background highlight
-               // TITLE_BACKGROUND_GRADIENT @ 40%
-               light = blend(titleBg, bg, 40);
-               // Full Highlight
-               // When *on* the title area (regions 1 and 2)
-               // Rule: If near the title in the 'hot' area, show background highlight
-               // TITLE_BACKGROUND_GRADIENT @ 60%
-               full = blend(titleBg, bg, 60);
-               // H_DND_LIGHT
-               // H_DND_FULL
-               createColor(IFormColors.H_HOVER_LIGHT, light);
-               createColor(IFormColors.H_HOVER_FULL, full);
-       }
-       
-       private LocalResourceManager getResourceManager() {
-               if (resources == null)
-                       resources = new LocalResourceManager(JFaceResources.getResources());
-               return resources;
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/FormFonts.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/FormFonts.java
deleted file mode 100644 (file)
index 9e931ba..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms;
-
-import java.util.HashMap;
-
-import org.eclipse.jface.resource.DeviceResourceException;
-import org.eclipse.jface.resource.FontDescriptor;
-import org.eclipse.jface.resource.JFaceResources;
-import org.eclipse.jface.resource.LocalResourceManager;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Device;
-import org.eclipse.swt.graphics.Font;
-import org.eclipse.swt.graphics.FontData;
-//import org.eclipse.swt.internal.graphics.Graphics;
-import org.eclipse.swt.widgets.Display;
-
-public class FormFonts {
-       private static FormFonts instance;
-
-       public static FormFonts getInstance() {
-               if (instance == null)
-                       instance = new FormFonts();
-               return instance;
-       }
-
-       private LocalResourceManager resources;
-       private HashMap descriptors;
-
-       private FormFonts() {
-       }
-
-       private class BoldFontDescriptor extends FontDescriptor {
-               private FontData[] fFontData;
-
-               BoldFontDescriptor(Font font) {
-                       // RAP [if] Changes due to different way of creating fonts
-                       // fFontData = font.getFontData();
-                       // for (int i = 0; i < fFontData.length; i++) {
-                       // fFontData[i].setStyle(fFontData[i].getStyle() | SWT.BOLD);
-                       // }
-                       FontData fontData = font.getFontData()[0];
-                       // Font boldFont = Graphics.getFont( fontData.getName(),
-                       // fontData.getHeight(),
-                       // fontData.getStyle() | SWT.BOLD );
-                       Font boldFont = new Font(Display.getCurrent(), fontData.getName(), fontData.getHeight(),
-                                       fontData.getStyle() | SWT.BOLD);
-                       fFontData = boldFont.getFontData();
-               }
-
-               public boolean equals(Object obj) {
-                       if (obj instanceof BoldFontDescriptor) {
-                               BoldFontDescriptor desc = (BoldFontDescriptor) obj;
-                               if (desc.fFontData.length != fFontData.length)
-                                       return false;
-                               for (int i = 0; i < fFontData.length; i++)
-                                       if (!fFontData[i].equals(desc.fFontData[i]))
-                                               return false;
-                               return true;
-                       }
-                       return false;
-               }
-
-               public int hashCode() {
-                       int hash = 0;
-                       for (int i = 0; i < fFontData.length; i++)
-                               hash = hash * 7 + fFontData[i].hashCode();
-                       return hash;
-               }
-
-               public Font createFont(Device device) throws DeviceResourceException {
-                       // RAP [if] Changes due to different way of creating fonts
-                       return new Font(device, fFontData[0]);
-                       // return Graphics.getFont( fFontData[ 0 ] );
-               }
-
-               public void destroyFont(Font previouslyCreatedFont) {
-                       // RAP [if] unnecessary
-                       // previouslyCreatedFont.dispose();
-               }
-       }
-
-       public Font getBoldFont(Display display, Font font) {
-               checkHashMaps();
-               BoldFontDescriptor desc = new BoldFontDescriptor(font);
-               Font result = getResourceManager().createFont(desc);
-               descriptors.put(result, desc);
-               return result;
-       }
-
-       public boolean markFinished(Font boldFont) {
-               checkHashMaps();
-               BoldFontDescriptor desc = (BoldFontDescriptor) descriptors.get(boldFont);
-               if (desc != null) {
-                       getResourceManager().destroyFont(desc);
-                       if (getResourceManager().find(desc) == null) {
-                               descriptors.remove(boldFont);
-                               validateHashMaps();
-                       }
-                       return true;
-
-               }
-               // if the image was not found, dispose of it for the caller
-               // RAP [if] unnecessary
-               // boldFont.dispose();
-               return false;
-       }
-
-       private LocalResourceManager getResourceManager() {
-               if (resources == null)
-                       resources = new LocalResourceManager(JFaceResources.getResources());
-               return resources;
-       }
-
-       private void checkHashMaps() {
-               if (descriptors == null)
-                       descriptors = new HashMap();
-       }
-
-       private void validateHashMaps() {
-               if (descriptors.size() == 0)
-                       descriptors = null;
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/FormToolkit.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/FormToolkit.java
deleted file mode 100644 (file)
index 9927104..0000000
+++ /dev/null
@@ -1,913 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms;
-
-import org.eclipse.jface.resource.JFaceResources;
-import org.eclipse.jface.window.Window;
-import org.eclipse.swt.SWT;
-//import org.eclipse.swt.custom.CCombo;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.events.FocusAdapter;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.KeyAdapter;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-// RAP [rh] Paint events missing
-//import org.eclipse.swt.events.PaintEvent;
-//import org.eclipse.swt.events.PaintListener;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.Font;
-//RAP [rh] GC missing
-//import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.graphics.Point;
-//import org.eclipse.swt.graphics.RGB;
-//import org.eclipse.swt.graphics.Rectangle;
-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.Event;
-import org.eclipse.swt.widgets.Label;
-//import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.Widget;
-//import org.eclipse.ui.forms.FormColors;
-//import org.eclipse.ui.forms.HyperlinkGroup;
-//import org.eclipse.ui.forms.IFormColors;
-//import org.eclipse.ui.internal.forms.widgets.FormFonts;
-//import org.eclipse.ui.internal.forms.widgets.FormUtil;
-
-/**
- * The toolkit is responsible for creating SWT controls adapted to work in
- * Eclipse forms. In addition to changing their presentation properties (fonts,
- * colors etc.), various listeners are attached to make them behave correctly in
- * the form context.
- * <p>
- * In addition to being the control factory, the toolkit is also responsible for
- * painting flat borders for select controls, managing hyperlink groups and
- * control colors.
- * <p>
- * The toolkit creates some of the most common controls used to populate Eclipse
- * forms. Controls that must be created using their constructors,
- * <code>adapt()</code> method is available to change its properties in the
- * same way as with the supported toolkit controls.
- * <p>
- * Typically, one toolkit object is created per workbench part (for example, an
- * editor or a form wizard). The toolkit is disposed when the part is disposed.
- * To conserve resources, it is possible to create one color object for the
- * entire plug-in and share it between several toolkits. The plug-in is
- * responsible for disposing the colors (disposing the toolkit that uses shared
- * color object will not dispose the colors).
- * <p>
- * FormToolkit is normally instantiated, but can also be subclassed if some of
- * the methods needs to be modified. In those cases, <code>super</code> must
- * be called to preserve normal behaviour.
- *
- * @since 1.0
- */
-public class FormToolkit {
-       public static final String KEY_DRAW_BORDER = "FormWidgetFactory.drawBorder"; //$NON-NLS-1$
-
-       public static final String TREE_BORDER = "treeBorder"; //$NON-NLS-1$
-
-       public static final String TEXT_BORDER = "textBorder"; //$NON-NLS-1$
-
-       private int borderStyle = SWT.NULL;
-
-       private FormColors colors;
-
-       private int orientation = Window.getDefaultOrientation();
-
-       // private KeyListener deleteListener;
-       // RAP [rh] Paint events missing
-//     private BorderPainter borderPainter;
-
-       private BoldFontHolder boldFontHolder;
-
-//     private HyperlinkGroup hyperlinkGroup;
-       
-       private boolean isDisposed = false;
-
-       /* default */
-       VisibilityHandler visibilityHandler;
-
-       /* default */
-       KeyboardHandler keyboardHandler;
-
-       // RAP [rh] Paint events missing
-//     private class BorderPainter implements PaintListener {
-//             public void paintControl(PaintEvent event) {
-//                     Composite composite = (Composite) event.widget;
-//                     Control[] children = composite.getChildren();
-//                     for (int i = 0; i < children.length; i++) {
-//                             Control c = children[i];
-//                             boolean inactiveBorder = false;
-//                             boolean textBorder = false;
-//                             if (!c.isVisible())
-//                                     continue;
-//                             /*
-//                              * if (c.getEnabled() == false && !(c instanceof CCombo))
-//                              * continue;
-//                              */
-//                             if (c instanceof Hyperlink)
-//                                     continue;
-//                             Object flag = c.getData(KEY_DRAW_BORDER);
-//                             if (flag != null) {
-//                                     if (flag.equals(Boolean.FALSE))
-//                                             continue;
-//                                     if (flag.equals(TREE_BORDER))
-//                                             inactiveBorder = true;
-//                                     else if (flag.equals(TEXT_BORDER))
-//                                             textBorder = true;
-//                             }
-//                             if (getBorderStyle() == SWT.BORDER) {
-//                                     if (!inactiveBorder && !textBorder) {
-//                                             continue;
-//                                     }
-//                                     if (c instanceof Text || c instanceof Table
-//                                                     || c instanceof Tree)
-//                                             continue;
-//                             }
-//                             if (!inactiveBorder
-//                                             && (c instanceof Text || c instanceof CCombo || textBorder)) {
-//                                     Rectangle b = c.getBounds();
-//                                     GC gc = event.gc;
-//                                     gc.setForeground(c.getBackground());
-//                                     gc.drawRectangle(b.x - 1, b.y - 1, b.width + 1,
-//                                                     b.height + 1);
-//                                     // gc.setForeground(getBorderStyle() == SWT.BORDER ? colors
-//                                     // .getBorderColor() : colors.getForeground());
-//                                     gc.setForeground(colors.getBorderColor());
-//                                     if (c instanceof CCombo)
-//                                             gc.drawRectangle(b.x - 1, b.y - 1, b.width + 1,
-//                                                             b.height + 1);
-//                                     else
-//                                             gc.drawRectangle(b.x - 1, b.y - 2, b.width + 1,
-//                                                             b.height + 3);
-//                             } else if (inactiveBorder || c instanceof Table
-//                                             || c instanceof Tree) {
-//                                     Rectangle b = c.getBounds();
-//                                     GC gc = event.gc;
-//                                     gc.setForeground(colors.getBorderColor());
-//                                     gc.drawRectangle(b.x - 1, b.y - 1, b.width + 1,
-//                                                     b.height + 1);
-//                             }
-//                     }
-//             }
-//     }
-
-       private static class VisibilityHandler extends FocusAdapter {
-               public void focusGained(FocusEvent e) {
-                       Widget w = e.widget;
-                       if (w instanceof Control) {
-                               FormUtil.ensureVisible((Control) w);
-                       }
-               }
-       }
-
-       private static class KeyboardHandler extends KeyAdapter {
-               public void keyPressed(KeyEvent e) {
-                       Widget w = e.widget;
-                       if (w instanceof Control) {
-                               if (e.doit)
-                                       FormUtil.processKey(e.keyCode, (Control) w);
-                       }
-               }
-       }
-
-       private class BoldFontHolder {
-               private Font normalFont;
-
-               private Font boldFont;
-
-               public BoldFontHolder() {
-               }
-
-               public Font getBoldFont(Font font) {
-                       createBoldFont(font);
-                       return boldFont;
-               }
-
-               private void createBoldFont(Font font) {
-                       if (normalFont == null || !normalFont.equals(font)) {
-                               normalFont = font;
-                               dispose();
-                       }
-                       if (boldFont == null) {
-                               boldFont = FormFonts.getInstance().getBoldFont(colors.getDisplay(),
-                                               normalFont);
-                       }
-               }
-
-               public void dispose() {
-                       if (boldFont != null) {
-                               FormFonts.getInstance().markFinished(boldFont);
-                               boldFont = null;
-                       }
-               }
-       }
-
-       /**
-        * Creates a toolkit that is self-sufficient (will manage its own colors).
-        * <p>
-        * Clients that call this method must call {@link #dispose()} when they
-        * are finished using the toolkit.
-        *
-        */
-       public FormToolkit(Display display) {
-               this(new FormColors(display));
-       }
-
-       /**
-        * Creates a toolkit that will use the provided (shared) colors. The toolkit
-        * will dispose the colors if and only if they are <b>not</b> marked as
-        * shared via the <code>markShared()</code> method.
-        * <p>
-        * Clients that call this method must call {@link #dispose()} when they
-        * are finished using the toolkit.
-        *
-        * @param colors
-        *            the shared colors
-        */
-       public FormToolkit(FormColors colors) {
-               this.colors = colors;
-               initialize();
-       }
-
-       /**
-        * Creates a button as a part of the form.
-        *
-        * @param parent
-        *            the button parent
-        * @param text
-        *            an optional text for the button (can be <code>null</code>)
-        * @param style
-        *            the button style (for example, <code>SWT.PUSH</code>)
-        * @return the button widget
-        */
-       public Button createButton(Composite parent, String text, int style) {
-               Button button = new Button(parent, style | SWT.FLAT | orientation);
-               if (text != null)
-                       button.setText(text);
-               adapt(button, true, true);
-               return button;
-       }
-
-       /**
-        * Creates the composite as a part of the form.
-        *
-        * @param parent
-        *            the composite parent
-        * @return the composite widget
-        */
-       public Composite createComposite(Composite parent) {
-               return createComposite(parent, SWT.NULL);
-       }
-
-       /**
-        * Creates the composite as part of the form using the provided style.
-        *
-        * @param parent
-        *            the composite parent
-        * @param style
-        *            the composite style
-        * @return the composite widget
-        */
-       public Composite createComposite(Composite parent, int style) {
-//             Composite composite = new LayoutComposite(parent, style | orientation);
-               Composite composite = new Composite(parent, style | orientation);
-               adapt(composite);
-               return composite;
-       }
-
-       /**
-        * Creats the composite that can server as a separator between various parts
-        * of a form. Separator height should be controlled by setting the height
-        * hint on the layout data for the composite.
-        *
-        * @param parent
-        *            the separator parent
-        * @return the separator widget
-        */
-// RAP [rh] createCompositeSeparator: currently no useful implementation possible, delete?
-       public Composite createCompositeSeparator(Composite parent) {
-               final Composite composite = new Composite(parent, orientation);
-// RAP [rh] GC and paint events missing
-//             composite.addListener(SWT.Paint, new Listener() {
-//                     public void handleEvent(Event e) {
-//                             if (composite.isDisposed())
-//                                     return;
-//                             Rectangle bounds = composite.getBounds();
-//                             GC gc = e.gc;
-//                             gc.setForeground(colors.getColor(IFormColors.SEPARATOR));
-//                             if (colors.getBackground() != null)
-//                                     gc.setBackground(colors.getBackground());
-//                             gc.fillGradientRectangle(0, 0, bounds.width, bounds.height,
-//                                             false);
-//                     }
-//             });
-//             if (parent instanceof Section)
-//                     ((Section) parent).setSeparatorControl(composite);
-               return composite;
-       }
-
-       /**
-        * Creates a label as a part of the form.
-        *
-        * @param parent
-        *            the label parent
-        * @param text
-        *            the label text
-        * @return the label widget
-        */
-       public Label createLabel(Composite parent, String text) {
-               return createLabel(parent, text, SWT.NONE);
-       }
-
-       /**
-        * Creates a label as a part of the form.
-        *
-        * @param parent
-        *            the label parent
-        * @param text
-        *            the label text
-        * @param style
-        *            the label style
-        * @return the label widget
-        */
-       public Label createLabel(Composite parent, String text, int style) {
-               Label label = new Label(parent, style | orientation);
-               if (text != null)
-                       label.setText(text);
-               adapt(label, false, false);
-               return label;
-       }
-
-       /**
-        * Creates a hyperlink as a part of the form. The hyperlink will be added to
-        * the hyperlink group that belongs to this toolkit.
-        *
-        * @param parent
-        *            the hyperlink parent
-        * @param text
-        *            the text of the hyperlink
-        * @param style
-        *            the hyperlink style
-        * @return the hyperlink widget
-        */
-//     public Hyperlink createHyperlink(Composite parent, String text, int style) {
-//             Hyperlink hyperlink = new Hyperlink(parent, style | orientation);
-//             if (text != null)
-//                     hyperlink.setText(text);
-//             hyperlink.addFocusListener(visibilityHandler);
-//             hyperlink.addKeyListener(keyboardHandler);
-//             hyperlinkGroup.add(hyperlink);
-//             return hyperlink;
-//     }
-
-       /**
-        * Creates an image hyperlink as a part of the form. The hyperlink will be
-        * added to the hyperlink group that belongs to this toolkit.
-        *
-        * @param parent
-        *            the hyperlink parent
-        * @param style
-        *            the hyperlink style
-        * @return the image hyperlink widget
-        */
-//     public ImageHyperlink createImageHyperlink(Composite parent, int style) {
-//             ImageHyperlink hyperlink = new ImageHyperlink(parent, style
-//                             | orientation);
-//             hyperlink.addFocusListener(visibilityHandler);
-//             hyperlink.addKeyListener(keyboardHandler);
-//             hyperlinkGroup.add(hyperlink);
-//             return hyperlink;
-//     }
-
-       /**
-        * Creates a rich text as a part of the form.
-        *
-        * @param parent
-        *            the rich text parent
-        * @param trackFocus
-        *            if <code>true</code>, the toolkit will monitor focus
-        *            transfers to ensure that the hyperlink in focus is visible in
-        *            the form.
-        * @return the rich text widget
-        * @since 1.2
-        */
-//     public FormText createFormText(Composite parent, boolean trackFocus) {
-//             FormText engine = new FormText(parent, SWT.WRAP | orientation);
-//             engine.marginWidth = 1;
-//             engine.marginHeight = 0;
-//             engine.setHyperlinkSettings(getHyperlinkGroup());
-//             adapt(engine, trackFocus, true);
-//             engine.setMenu(parent.getMenu());
-//             return engine;
-//     }
-
-       /**
-        * Adapts a control to be used in a form that is associated with this
-        * toolkit. This involves adjusting colors and optionally adding handlers to
-        * ensure focus tracking and keyboard management.
-        *
-        * @param control
-        *            a control to adapt
-        * @param trackFocus
-        *            if <code>true</code>, form will be scrolled horizontally
-        *            and/or vertically if needed to ensure that the control is
-        *            visible when it gains focus. Set it to <code>false</code> if
-        *            the control is not capable of gaining focus.
-        * @param trackKeyboard
-        *            if <code>true</code>, the control that is capable of
-        *            gaining focus will be tracked for certain keys that are
-        *            important to the underlying form (for example, PageUp,
-        *            PageDown, ScrollUp, ScrollDown etc.). Set it to
-        *            <code>false</code> if the control is not capable of gaining
-        *            focus or these particular key event are already used by the
-        *            control.
-        */
-       public void adapt(Control control, boolean trackFocus, boolean trackKeyboard) {
-               control.setBackground(colors.getBackground());
-               control.setForeground(colors.getForeground());
-//             if (control instanceof ExpandableComposite) {
-//                     ExpandableComposite ec = (ExpandableComposite) control;
-//                     if (ec.toggle != null) {
-//                             if (trackFocus)
-//                                     ec.toggle.addFocusListener(visibilityHandler);
-//                             if (trackKeyboard)
-//                                     ec.toggle.addKeyListener(keyboardHandler);
-//                     }
-//                     if (ec.textLabel != null) {
-//                             if (trackFocus)
-//                                     ec.textLabel.addFocusListener(visibilityHandler);
-//                             if (trackKeyboard)
-//                                     ec.textLabel.addKeyListener(keyboardHandler);
-//                     }
-//                     return;
-//             }
-               if (trackFocus)
-                       control.addFocusListener(visibilityHandler);
-               if (trackKeyboard)
-                       control.addKeyListener(keyboardHandler);
-       }
-
-       /**
-        * Adapts a composite to be used in a form associated with this toolkit.
-        *
-        * @param composite
-        *            the composite to adapt
-        */
-       public void adapt(Composite composite) {
-               composite.setBackground(colors.getBackground());
-               composite.addMouseListener(new MouseAdapter() {
-                       public void mouseDown(MouseEvent e) {
-                               ((Control) e.widget).setFocus();
-                       }
-               });
-               if (composite.getParent() != null)
-                       composite.setMenu(composite.getParent().getMenu());
-       }
-
-       /**
-        * A helper method that ensures the provided control is visible when
-        * ScrolledComposite is somewhere in the parent chain. If scroll bars are
-        * visible and the control is clipped, the client of the scrolled composite
-        * will be scrolled to reveal the control.
-        *
-        * @param c
-        *            the control to reveal
-        */
-       public static void ensureVisible(Control c) {
-               FormUtil.ensureVisible(c);
-       }
-
-       /**
-        * Creates a section as a part of the form.
-        *
-        * @param parent
-        *            the section parent
-        * @param sectionStyle
-        *            the section style
-        * @return the section widget
-        */
-//     public Section createSection(Composite parent, int sectionStyle) {
-//             Section section = new Section(parent, orientation, sectionStyle);
-//             section.setMenu(parent.getMenu());
-//             adapt(section, true, true);
-//             if (section.toggle != null) {
-//                     section.toggle.setHoverDecorationColor(colors
-//                                     .getColor(IFormColors.TB_TOGGLE_HOVER));
-//                     section.toggle.setDecorationColor(colors
-//                                     .getColor(IFormColors.TB_TOGGLE));
-//             }
-//             section.setFont(boldFontHolder.getBoldFont(parent.getFont()));
-//             if ((sectionStyle & Section.TITLE_BAR) != 0
-//                             || (sectionStyle & Section.SHORT_TITLE_BAR) != 0) {
-//                     colors.initializeSectionToolBarColors();
-//                     section.setTitleBarBackground(colors.getColor(IFormColors.TB_BG));
-//                     section.setTitleBarBorderColor(colors
-//                                     .getColor(IFormColors.TB_BORDER));
-//             }
-//             // call setTitleBarForeground regardless as it also sets the label color
-//             section.setTitleBarForeground(colors
-//                             .getColor(IFormColors.TB_TOGGLE));
-//             return section;
-//     }
-
-       /**
-        * Creates an expandable composite as a part of the form.
-        *
-        * @param parent
-        *            the expandable composite parent
-        * @param expansionStyle
-        *            the expandable composite style
-        * @return the expandable composite widget
-        */
-//     public ExpandableComposite createExpandableComposite(Composite parent,
-//                     int expansionStyle) {
-//             ExpandableComposite ec = new ExpandableComposite(parent, orientation,
-//                             expansionStyle);
-//             ec.setMenu(parent.getMenu());
-//             adapt(ec, true, true);
-//             ec.setFont(boldFontHolder.getBoldFont(ec.getFont()));
-//             return ec;
-//     }
-
-       /**
-        * Creates a separator label as a part of the form.
-        *
-        * @param parent
-        *            the separator parent
-        * @param style
-        *            the separator style
-        * @return the separator label
-        */
-       public Label createSeparator(Composite parent, int style) {
-               Label label = new Label(parent, SWT.SEPARATOR | style | orientation);
-               label.setBackground(colors.getBackground());
-               label.setForeground(colors.getBorderColor());
-               return label;
-       }
-
-       /**
-        * Creates a table as a part of the form.
-        *
-        * @param parent
-        *            the table parent
-        * @param style
-        *            the table style
-        * @return the table widget
-        */
-       public Table createTable(Composite parent, int style) {
-               Table table = new Table(parent, style | borderStyle | orientation);
-               adapt(table, false, false);
-               // hookDeleteListener(table);
-               return table;
-       }
-
-       /**
-        * Creates a text as a part of the form.
-        *
-        * @param parent
-        *            the text parent
-        * @param value
-        *            the text initial value
-        * @return the text widget
-        */
-       public Text createText(Composite parent, String value) {
-               return createText(parent, value, SWT.SINGLE);
-       }
-
-       /**
-        * Creates a text as a part of the form.
-        *
-        * @param parent
-        *            the text parent
-        * @param value
-        *            the text initial value
-        * @param style
-        *            the text style
-        * @return the text widget
-        */
-       public Text createText(Composite parent, String value, int style) {
-               Text text = new Text(parent, borderStyle | style | orientation);
-               if (value != null)
-                       text.setText(value);
-               text.setForeground(colors.getForeground());
-               text.setBackground(colors.getBackground());
-               text.addFocusListener(visibilityHandler);
-               return text;
-       }
-
-       /**
-        * Creates a tree widget as a part of the form.
-        *
-        * @param parent
-        *            the tree parent
-        * @param style
-        *            the tree style
-        * @return the tree widget
-        */
-       public Tree createTree(Composite parent, int style) {
-               Tree tree = new Tree(parent, borderStyle | style | orientation);
-               adapt(tree, false, false);
-               // hookDeleteListener(tree);
-               return tree;
-       }
-
-       /**
-        * Creates a scrolled form widget in the provided parent. If you do not
-        * require scrolling because there is already a scrolled composite up the
-        * parent chain, use 'createForm' instead.
-        *
-        * @param parent
-        *            the scrolled form parent
-        * @return the form that can scroll itself
-        * @see #createForm
-        */
-       public ScrolledComposite createScrolledForm(Composite parent) {
-               ScrolledComposite form = new ScrolledComposite(parent, SWT.V_SCROLL
-                               | SWT.H_SCROLL | orientation);
-               form.setExpandHorizontal(true);
-               form.setExpandVertical(true);
-               form.setBackground(colors.getBackground());
-               form.setForeground(colors.getColor(IFormColors.TITLE));
-               form.setFont(JFaceResources.getHeaderFont());
-               return form;
-       }
-
-       /**
-        * Creates a form widget in the provided parent. Note that this widget does
-        * not scroll its content, so make sure there is a scrolled composite up the
-        * parent chain. If you require scrolling, use 'createScrolledForm' instead.
-        *
-        * @param parent
-        *            the form parent
-        * @return the form that does not scroll
-        * @see #createScrolledForm
-        */
-//     public Form createForm(Composite parent) {
-//             Form formContent = new Form(parent, orientation);
-//             formContent.setBackground(colors.getBackground());
-//             formContent.setForeground(colors.getColor(IFormColors.TITLE));
-//             formContent.setFont(JFaceResources.getHeaderFont());
-//             return formContent;
-//     }
-
-       /**
-        * Takes advantage of the gradients and other capabilities to decorate the
-        * form heading using colors computed based on the current skin and
-        * operating system.
-        *
-        * @param form
-        *            the form to decorate
-        */
-
-//     public void decorateFormHeading(Form form) {
-//             Color top = colors.getColor(IFormColors.H_GRADIENT_END);
-//             Color bot = colors.getColor(IFormColors.H_GRADIENT_START);
-//             form.setTextBackground(new Color[] { top, bot }, new int[] { 100 },
-//                             true);
-//             form.setHeadColor(IFormColors.H_BOTTOM_KEYLINE1, colors
-//                             .getColor(IFormColors.H_BOTTOM_KEYLINE1));
-//             form.setHeadColor(IFormColors.H_BOTTOM_KEYLINE2, colors
-//                             .getColor(IFormColors.H_BOTTOM_KEYLINE2));
-//             form.setHeadColor(IFormColors.H_HOVER_LIGHT, colors
-//                             .getColor(IFormColors.H_HOVER_LIGHT));
-//             form.setHeadColor(IFormColors.H_HOVER_FULL, colors
-//                             .getColor(IFormColors.H_HOVER_FULL));
-//             form.setHeadColor(IFormColors.TB_TOGGLE, colors
-//                             .getColor(IFormColors.TB_TOGGLE));
-//             form.setHeadColor(IFormColors.TB_TOGGLE_HOVER, colors
-//                             .getColor(IFormColors.TB_TOGGLE_HOVER));
-//             form.setSeparatorVisible(true);
-//     }
-
-       /**
-        * Creates a scrolled page book widget as a part of the form.
-        *
-        * @param parent
-        *            the page book parent
-        * @param style
-        *            the text style
-        * @return the scrolled page book widget
-        */
-//     public ScrolledPageBook createPageBook(Composite parent, int style) {
-//             ScrolledPageBook book = new ScrolledPageBook(parent, style
-//                             | orientation);
-//             adapt(book, true, true);
-//             book.setMenu(parent.getMenu());
-//             return book;
-//     }
-
-       /**
-        * Disposes the toolkit.
-        */
-       public void dispose() {
-               if (isDisposed) {
-                       return;
-               }
-               isDisposed = true;
-               if (colors.isShared() == false) {
-                       colors.dispose();
-                       colors = null;
-               }
-               boldFontHolder.dispose();
-       }
-
-       /**
-        * Returns the hyperlink group that manages hyperlinks for this toolkit.
-        *
-        * @return the hyperlink group
-        */
-//     public HyperlinkGroup getHyperlinkGroup() {
-//             return hyperlinkGroup;
-//     }
-
-       /**
-        * Sets the background color for the entire toolkit. The method delegates
-        * the call to the FormColors object and also updates the hyperlink group so
-        * that hyperlinks and other objects are in sync.
-        *
-        * @param bg
-        *            the new background color
-        */
-       public void setBackground(Color bg) {
-//             hyperlinkGroup.setBackground(bg);
-               colors.setBackground(bg);
-       }
-
-       /**
-        * Refreshes the hyperlink colors by loading from JFace settings.
-        */
-//     public void refreshHyperlinkColors() {
-//             hyperlinkGroup.initializeDefaultForegrounds(colors.getDisplay());
-//     }
-
-// RAP [rh] paintBordersFor not useful as no GC to actually paint borders
-//     /**
-//      * Paints flat borders for widgets created by this toolkit within the
-//      * provided parent. Borders will not be painted if the global border style
-//      * is SWT.BORDER (i.e. if native borders are used). Call this method during
-//      * creation of a form composite to get the borders of its children painted.
-//      * Care should be taken when selection layout margins. At least one pixel
-//      * pargin width and height must be chosen to allow the toolkit to paint the
-//      * border on the parent around the widgets.
-//      * <p>
-//      * Borders are painted for some controls that are selected by the toolkit by
-//      * default. If a control needs a border but is not on its list, it is
-//      * possible to force border in the following way:
-//      *
-//      * <pre>
-//      *
-//      *
-//      *
-//      *             widget.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER);
-//      *
-//      *             or
-//      *
-//      *             widget.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
-//      *
-//      *
-//      *
-//      * </pre>
-//      *
-//      * @param parent
-//      *            the parent that owns the children for which the border needs
-//      *            to be painted.
-//      */
-//     public void paintBordersFor(Composite parent) {
-//             // if (borderStyle == SWT.BORDER)
-//             // return;
-//             if (borderPainter == null)
-//                     borderPainter = new BorderPainter();
-//             parent.addPaintListener(borderPainter);
-//     }
-
-       /**
-        * Returns the colors used by this toolkit.
-        *
-        * @return the color object
-        */
-       public FormColors getColors() {
-               return colors;
-       }
-
-       /**
-        * Returns the border style used for various widgets created by this
-        * toolkit. The intent of the toolkit is to create controls with styles that
-        * yield a 'flat' appearance. On systems where the native borders are
-        * already flat, we set the style to SWT.BORDER and don't paint the borders
-        * ourselves. Otherwise, the style is set to SWT.NULL, and borders are
-        * painted by the toolkit.
-        *
-        * @return the global border style
-        */
-       public int getBorderStyle() {
-               return borderStyle;
-       }
-
-       /**
-        * Returns the margin required around the children whose border is being
-        * painted by the toolkit using {@link #paintBordersFor(Composite)}. Since
-        * the border is painted around the controls on the parent, a number of
-        * pixels needs to be reserved for this border. For windowing systems where
-        * the native border is used, this margin is 0.
-        *
-        * @return the margin in the parent when children have their border painted
-        */
-       public int getBorderMargin() {
-               return getBorderStyle() == SWT.BORDER ? 0 : 2;
-       }
-
-       /**
-        * Sets the border style to be used when creating widgets. The toolkit
-        * chooses the correct style based on the platform but this value can be
-        * changed using this method.
-        *
-        * @param style
-        *            <code>SWT.BORDER</code> or <code>SWT.NULL</code>
-        * @see #getBorderStyle
-        */
-       public void setBorderStyle(int style) {
-               this.borderStyle = style;
-       }
-
-       /**
-        * A utility method that ensures that the control is visible in the scrolled
-        * composite. The prerequisite for this method is that the control has a
-        * class that extends ScrolledComposite somewhere in the parent chain. If
-        * the control is partially or fully clipped, the composite is scrolled to
-        * set by setting the origin to the control origin.
-        *
-        * @param c
-        *            the control to make visible
-        * @param verticalOnly
-        *            if <code>true</code>, the scrolled composite will be
-        *            scrolled only vertically if needed. Otherwise, the scrolled
-        *            composite origin will be set to the control origin.
-        */
-       public static void setControlVisible(Control c, boolean verticalOnly) {
-               ScrolledComposite scomp = FormUtil.getScrolledComposite(c);
-               if (scomp == null)
-                       return;
-               Point location = FormUtil.getControlLocation(scomp, c);
-               scomp.setOrigin(location);
-       }
-
-       private void initialize() {
-               initializeBorderStyle();
-//             hyperlinkGroup = new HyperlinkGroup(colors.getDisplay());
-//             hyperlinkGroup.setBackground(colors.getBackground());
-               visibilityHandler = new VisibilityHandler();
-               keyboardHandler = new KeyboardHandler();
-               boldFontHolder = new BoldFontHolder();
-       }
-
-// RAP [rh] revise detection of border style: can't ask OS here
-       private void initializeBorderStyle() {
-//             String osname = System.getProperty("os.name"); //$NON-NLS-1$
-//             String osversion = System.getProperty("os.version"); //$NON-NLS-1$
-//             if (osname.startsWith("Windows") && "5.1".compareTo(osversion) <= 0) { //$NON-NLS-1$ //$NON-NLS-2$
-//                     // Skinned widgets used on newer Windows (e.g. XP (5.1), Vista
-//                     // (6.0))
-//                     // Check for Windows Classic. If not used, set the style to BORDER
-//                     RGB rgb = colors.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
-//                     if (rgb.red != 212 || rgb.green != 208 || rgb.blue != 200)
-//                             borderStyle = SWT.BORDER;
-//             } else if (osname.startsWith("Mac")) //$NON-NLS-1$
-//                     borderStyle = SWT.BORDER;
-
-               borderStyle = SWT.BORDER;
-       }
-
-       /**
-        * Returns the orientation that all the widgets created by this toolkit will
-        * inherit, if set. Can be <code>SWT.NULL</code>,
-        * <code>SWT.LEFT_TO_RIGHT</code> and <code>SWT.RIGHT_TO_LEFT</code>.
-        *
-        * @return orientation style for this toolkit, or <code>SWT.NULL</code> if
-        *         not set. The default orientation is inherited from the Window
-        *         default orientation.
-        * @see org.eclipse.jface.window.Window#getDefaultOrientation()
-        */
-
-       public int getOrientation() {
-               return orientation;
-       }
-
-       /**
-        * Sets the orientation that all the widgets created by this toolkit will
-        * inherit. Can be <code>SWT.NULL</code>, <code>SWT.LEFT_TO_RIGHT</code>
-        * and <code>SWT.RIGHT_TO_LEFT</code>.
-        *
-        * @param orientation
-        *            style for this toolkit.
-        */
-
-       public void setOrientation(int orientation) {
-               this.orientation = orientation;
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/FormUtil.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/FormUtil.java
deleted file mode 100644 (file)
index 76e3f11..0000000
+++ /dev/null
@@ -1,522 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.events.MouseEvent;
-//import org.eclipse.swt.graphics.Device;
-import org.eclipse.swt.graphics.FontMetrics;
-import org.eclipse.swt.graphics.GC;
-//import org.eclipse.swt.graphics.Image;
-//import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Combo;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Layout;
-//import org.eclipse.swt.widgets.ScrollBar;
-import org.eclipse.swt.widgets.Text;
-//import org.eclipse.ui.forms.widgets.ColumnLayout;
-//import org.eclipse.ui.forms.widgets.Form;
-//import org.eclipse.ui.forms.widgets.FormText;
-//import org.eclipse.ui.forms.widgets.FormToolkit;
-//import org.eclipse.ui.forms.widgets.ILayoutExtension;
-//
-//import com.ibm.icu.text.BreakIterator;
-
-public class FormUtil {
-       public static final String PLUGIN_ID = "org.eclipse.ui.forms"; //$NON-NLS-1$
-
-       static final int H_SCROLL_INCREMENT = 5;
-
-       static final int V_SCROLL_INCREMENT = 64;
-
-       public static final String DEBUG = PLUGIN_ID + "/debug"; //$NON-NLS-1$
-
-       public static final String DEBUG_TEXT = DEBUG + "/text"; //$NON-NLS-1$
-       public static final String DEBUG_TEXTSIZE = DEBUG + "/textsize"; //$NON-NLS-1$
-
-       public static final String DEBUG_FOCUS = DEBUG + "/focus"; //$NON-NLS-1$
-
-       public static final String FOCUS_SCROLLING = "focusScrolling"; //$NON-NLS-1$
-       
-       public static final String IGNORE_BODY = "__ignore_body__"; //$NON-NLS-1$
-
-       public static Text createText(Composite parent, String label,
-                       FormToolkit factory) {
-               return createText(parent, label, factory, 1);
-       }
-
-       public static Text createText(Composite parent, String label,
-                       FormToolkit factory, int span) {
-               factory.createLabel(parent, label);
-               Text text = factory.createText(parent, ""); //$NON-NLS-1$
-               int hfill = span == 1 ? GridData.FILL_HORIZONTAL
-                               : GridData.HORIZONTAL_ALIGN_FILL;
-               GridData gd = new GridData(hfill | GridData.VERTICAL_ALIGN_CENTER);
-               gd.horizontalSpan = span;
-               text.setLayoutData(gd);
-               return text;
-       }
-
-       public static Text createText(Composite parent, String label,
-                       FormToolkit factory, int span, int style) {
-               Label l = factory.createLabel(parent, label);
-               if ((style & SWT.MULTI) != 0) {
-                       GridData gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
-                       l.setLayoutData(gd);
-               }
-               Text text = factory.createText(parent, "", style); //$NON-NLS-1$
-               int hfill = span == 1 ? GridData.FILL_HORIZONTAL
-                               : GridData.HORIZONTAL_ALIGN_FILL;
-               GridData gd = new GridData(hfill | GridData.VERTICAL_ALIGN_CENTER);
-               gd.horizontalSpan = span;
-               text.setLayoutData(gd);
-               return text;
-       }
-
-       public static Text createText(Composite parent, FormToolkit factory,
-                       int span) {
-               Text text = factory.createText(parent, ""); //$NON-NLS-1$
-               int hfill = span == 1 ? GridData.FILL_HORIZONTAL
-                               : GridData.HORIZONTAL_ALIGN_FILL;
-               GridData gd = new GridData(hfill | GridData.VERTICAL_ALIGN_CENTER);
-               gd.horizontalSpan = span;
-               text.setLayoutData(gd);
-               return text;
-       }
-
-       public static int computeMinimumWidth(GC gc, String text) {
-//             BreakIterator wb = BreakIterator.getWordInstance();
-//             wb.setText(text);
-//             int last = 0;
-//
-//             int width = 0;
-//
-//             for (int loc = wb.first(); loc != BreakIterator.DONE; loc = wb.next()) {
-//                     String word = text.substring(last, loc);
-//                     Point extent = gc.textExtent(word);
-//                     width = Math.max(width, extent.x);
-//                     last = loc;
-//             }
-//             String lastWord = text.substring(last);
-//             Point extent = gc.textExtent(lastWord);
-//             width = Math.max(width, extent.x);
-//             return width;
-               return 0;
-       }
-       
-       public static Point computeWrapSize(GC gc, String text, int wHint) {    
-//             BreakIterator wb = BreakIterator.getWordInstance();
-//             wb.setText(text);
-               FontMetrics fm = gc.getFontMetrics();
-               int lineHeight = fm.getHeight();
-               
-               int saved = 0;
-               int last = 0;
-               int height = lineHeight;
-               int maxWidth = 0;
-//             for (int loc = wb.first(); loc != BreakIterator.DONE; loc = wb.next()) {
-//                     String word = text.substring(saved, loc);
-//                     Point extent = gc.textExtent(word);
-//                     if (extent.x > wHint) {
-//                             // overflow
-//                             saved = last;
-//                             height += extent.y;
-//                             // switch to current word so maxWidth will accommodate very long single words
-//                             word = text.substring(last, loc);
-//                             extent = gc.textExtent(word);
-//                     }
-//                     maxWidth = Math.max(maxWidth, extent.x);
-//                     last = loc;
-//             }
-               /*
-                * Correct the height attribute in case it was calculated wrong due to wHint being less than maxWidth.
-                * The recursive call proved to be the only thing that worked in all cases. Some attempts can be made
-                * to estimate the height, but the algorithm needs to be run again to be sure.
-                */
-               if (maxWidth > wHint)
-                       return computeWrapSize(gc, text, maxWidth);               
-               return new Point(maxWidth, height);
-       }
-
-// RAP [rh] paintWrapText unnecessary
-//     public static void paintWrapText(GC gc, String text, Rectangle bounds) {
-//             paintWrapText(gc, text, bounds, false);
-//     }
-       
-// RAP [rh] paintWrapText unnecessary
-//     public static void paintWrapText(GC gc, String text, Rectangle bounds,
-//                     boolean underline) {
-//             BreakIterator wb = BreakIterator.getWordInstance();
-//             wb.setText(text);
-//             FontMetrics fm = gc.getFontMetrics();
-//             int lineHeight = fm.getHeight();
-//             int descent = fm.getDescent();
-//
-//             int saved = 0;
-//             int last = 0;
-//             int y = bounds.y;
-//             int width = bounds.width;
-//
-//             for (int loc = wb.first(); loc != BreakIterator.DONE; loc = wb.next()) {
-//                     String line = text.substring(saved, loc);
-//                     Point extent = gc.textExtent(line);
-//
-//                     if (extent.x > width) {
-//                             // overflow
-//                             String prevLine = text.substring(saved, last);
-//                             gc.drawText(prevLine, bounds.x, y, true);
-//                             if (underline) {
-//                                     Point prevExtent = gc.textExtent(prevLine);
-//                                     int lineY = y + lineHeight - descent + 1;
-//                                     gc
-//                                                     .drawLine(bounds.x, lineY, bounds.x + prevExtent.x,
-//                                                                     lineY);
-//                             }
-//
-//                             saved = last;
-//                             y += lineHeight;
-//                     }
-//                     last = loc;
-//             }
-//             // paint the last line
-//             String lastLine = text.substring(saved, last);
-//             gc.drawText(lastLine, bounds.x, y, true);
-//             if (underline) {
-//                     int lineY = y + lineHeight - descent + 1;
-//                     Point lastExtent = gc.textExtent(lastLine);
-//                     gc.drawLine(bounds.x, lineY, bounds.x + lastExtent.x, lineY);
-//             }
-//     }
-
-       public static ScrolledComposite getScrolledComposite(Control c) {
-               Composite parent = c.getParent();
-
-               while (parent != null) {
-                       if (parent instanceof ScrolledComposite) {
-                               return (ScrolledComposite) parent;
-                       }
-                       parent = parent.getParent();
-               }
-               return null;
-       }
-
-       public static void ensureVisible(Control c) {
-               ScrolledComposite scomp = getScrolledComposite(c);
-               if (scomp != null) {
-                       Object data = scomp.getData(FOCUS_SCROLLING);
-                       if (data == null || !data.equals(Boolean.FALSE))
-                               FormUtil.ensureVisible(scomp, c);
-               }
-       }
-
-       public static void ensureVisible(ScrolledComposite scomp, Control control) {
-               // if the control is a FormText we do not need to scroll since it will
-               // ensure visibility of its segments as necessary
-//             if (control instanceof FormText)
-//                     return;
-               Point controlSize = control.getSize();
-               Point controlOrigin = getControlLocation(scomp, control);
-               ensureVisible(scomp, controlOrigin, controlSize);
-       }
-
-       public static void ensureVisible(ScrolledComposite scomp,
-                       Point controlOrigin, Point controlSize) {
-               Rectangle area = scomp.getClientArea();
-               Point scompOrigin = scomp.getOrigin();
-
-               int x = scompOrigin.x;
-               int y = scompOrigin.y;
-
-               // horizontal right, but only if the control is smaller
-               // than the client area
-               if (controlSize.x < area.width
-                               && (controlOrigin.x + controlSize.x > scompOrigin.x
-                                               + area.width)) {
-                       x = controlOrigin.x + controlSize.x - area.width;
-               }
-               // horizontal left - make sure the left edge of
-               // the control is showing
-               if (controlOrigin.x < x) {
-                       if (controlSize.x < area.width)
-                               x = controlOrigin.x + controlSize.x - area.width;
-                       else
-                               x = controlOrigin.x;
-               }
-               // vertical bottom
-               if (controlSize.y < area.height
-                               && (controlOrigin.y + controlSize.y > scompOrigin.y
-                                               + area.height)) {
-                       y = controlOrigin.y + controlSize.y - area.height;
-               }
-               // vertical top - make sure the top of
-               // the control is showing
-               if (controlOrigin.y < y) {
-                       if (controlSize.y < area.height)
-                               y = controlOrigin.y + controlSize.y - area.height;
-                       else
-                               y = controlOrigin.y;
-               }
-
-               if (scompOrigin.x != x || scompOrigin.y != y) {
-                       // scroll to reveal
-                       scomp.setOrigin(x, y);
-               }
-       }
-
-       public static void ensureVisible(ScrolledComposite scomp, Control control,
-                       MouseEvent e) {
-               Point controlOrigin = getControlLocation(scomp, control);
-               int rX = controlOrigin.x + e.x;
-               int rY = controlOrigin.y + e.y;
-               Rectangle area = scomp.getClientArea();
-               Point scompOrigin = scomp.getOrigin();
-
-               int x = scompOrigin.x;
-               int y = scompOrigin.y;
-               // System.out.println("Ensure: area="+area+", origin="+scompOrigin+",
-               // cloc="+controlOrigin+", csize="+controlSize+", x="+x+", y="+y);
-
-               // horizontal right
-               if (rX > scompOrigin.x + area.width) {
-                       x = rX - area.width;
-               }
-               // horizontal left
-               else if (rX < x) {
-                       x = rX;
-               }
-               // vertical bottom
-               if (rY > scompOrigin.y + area.height) {
-                       y = rY - area.height;
-               }
-               // vertical top
-               else if (rY < y) {
-                       y = rY;
-               }
-
-               if (scompOrigin.x != x || scompOrigin.y != y) {
-                       // scroll to reveal
-                       scomp.setOrigin(x, y);
-               }
-       }
-
-       public static Point getControlLocation(ScrolledComposite scomp,
-                       Control control) {
-               int x = 0;
-               int y = 0;
-               Control content = scomp.getContent();
-               Control currentControl = control;
-               for (;;) {
-                       if (currentControl == content)
-                               break;
-                       Point location = currentControl.getLocation();
-                       // if (location.x > 0)
-                       // x += location.x;
-                       // if (location.y > 0)
-                       // y += location.y;
-                       x += location.x;
-                       y += location.y;
-                       currentControl = currentControl.getParent();
-               }
-               return new Point(x, y);
-       }
-
-       static void scrollVertical(ScrolledComposite scomp, boolean up) {
-               scroll(scomp, 0, up ? -V_SCROLL_INCREMENT : V_SCROLL_INCREMENT);
-       }
-
-       static void scrollHorizontal(ScrolledComposite scomp, boolean left) {
-               scroll(scomp, left ? -H_SCROLL_INCREMENT : H_SCROLL_INCREMENT, 0);
-       }
-
-       static void scrollPage(ScrolledComposite scomp, boolean up) {
-               Rectangle clientArea = scomp.getClientArea();
-               int increment = up ? -clientArea.height : clientArea.height;
-               scroll(scomp, 0, increment);
-       }
-
-       static void scroll(ScrolledComposite scomp, int xoffset, int yoffset) {
-               Point origin = scomp.getOrigin();
-               Point contentSize = scomp.getContent().getSize();
-               int xorigin = origin.x + xoffset;
-               int yorigin = origin.y + yoffset;
-               xorigin = Math.max(xorigin, 0);
-               xorigin = Math.min(xorigin, contentSize.x - 1);
-               yorigin = Math.max(yorigin, 0);
-               yorigin = Math.min(yorigin, contentSize.y - 1);
-               scomp.setOrigin(xorigin, yorigin);
-       }
-
-// RAP [rh] FormUtil#updatePageIncrement: empty implementation
-       public static void updatePageIncrement(ScrolledComposite scomp) {
-//             ScrollBar vbar = scomp.getVerticalBar();
-//             if (vbar != null) {
-//                     Rectangle clientArea = scomp.getClientArea();
-//                     int increment = clientArea.height - 5;
-//                     vbar.setPageIncrement(increment);
-//             }
-//             ScrollBar hbar = scomp.getHorizontalBar();
-//             if (hbar != null) {
-//                     Rectangle clientArea = scomp.getClientArea();
-//                     int increment = clientArea.width - 5;
-//                     hbar.setPageIncrement(increment);
-//             }
-       }
-
-       public static void processKey(int keyCode, Control c) {
-               if (c.isDisposed()) {
-                       return;
-               }
-               ScrolledComposite scomp = FormUtil.getScrolledComposite(c);
-               if (scomp != null) {
-                       if (c instanceof Combo)
-                               return;
-                       switch (keyCode) {
-                       case SWT.ARROW_DOWN:
-                               if (scomp.getData("novarrows") == null) //$NON-NLS-1$
-                                       FormUtil.scrollVertical(scomp, false);
-                               break;
-                       case SWT.ARROW_UP:
-                               if (scomp.getData("novarrows") == null) //$NON-NLS-1$
-                                       FormUtil.scrollVertical(scomp, true);
-                               break;
-                       case SWT.ARROW_LEFT:
-                               FormUtil.scrollHorizontal(scomp, true);
-                               break;
-                       case SWT.ARROW_RIGHT:
-                               FormUtil.scrollHorizontal(scomp, false);
-                               break;
-                       case SWT.PAGE_UP:
-                               FormUtil.scrollPage(scomp, true);
-                               break;
-                       case SWT.PAGE_DOWN:
-                               FormUtil.scrollPage(scomp, false);
-                               break;
-                       }
-               }
-       }
-
-       public static boolean isWrapControl(Control c) {
-               if ((c.getStyle() & SWT.WRAP) != 0)
-                       return true;
-               if (c instanceof Composite) {
-                       return false;
-//                     return ((Composite) c).getLayout() instanceof ILayoutExtension;
-               }
-               return false;
-       }
-
-       public static int getWidthHint(int wHint, Control c) {
-               boolean wrap = isWrapControl(c);
-               return wrap ? wHint : SWT.DEFAULT;
-       }
-
-       public static int getHeightHint(int hHint, Control c) {
-               if (c instanceof Composite) {
-                       Layout layout = ((Composite) c).getLayout();
-//                     if (layout instanceof ColumnLayout)
-//                             return hHint;
-               }
-               return SWT.DEFAULT;
-       }
-
-       public static int computeMinimumWidth(Control c, boolean changed) {
-               if (c instanceof Composite) {
-                       Layout layout = ((Composite) c).getLayout();
-//                     if (layout instanceof ILayoutExtension)
-//                             return ((ILayoutExtension) layout).computeMinimumWidth(
-//                                             (Composite) c, changed);
-               }
-               return c.computeSize(FormUtil.getWidthHint(5, c), SWT.DEFAULT, changed).x;
-       }
-
-       public static int computeMaximumWidth(Control c, boolean changed) {
-               if (c instanceof Composite) {
-                       Layout layout = ((Composite) c).getLayout();
-//                     if (layout instanceof ILayoutExtension)
-//                             return ((ILayoutExtension) layout).computeMaximumWidth(
-//                                             (Composite) c, changed);
-               }
-               return c.computeSize(SWT.DEFAULT, SWT.DEFAULT, changed).x;
-       }
-
-//     public static Form getForm(Control c) {
-//             Composite parent = c.getParent();
-//             while (parent != null) {
-//                     if (parent instanceof Form) {
-//                             return (Form) parent;
-//                     }
-//                     parent = parent.getParent();
-//             }
-//             return null;
-//     }
-
-// RAP [rh] FormUtil#createAlphaMashImage unnecessary  
-//     public static Image createAlphaMashImage(Device device, Image srcImage) {
-//             Rectangle bounds = srcImage.getBounds();
-//             int alpha = 0;
-//             int calpha = 0;
-//             ImageData data = srcImage.getImageData();
-//             // Create a new image with alpha values alternating
-//             // between fully transparent (0) and fully opaque (255).
-//             // This image will show the background through the
-//             // transparent pixels.
-//             for (int i = 0; i < bounds.height; i++) {
-//                     // scan line
-//                     alpha = calpha;
-//                     for (int j = 0; j < bounds.width; j++) {
-//                             // column
-//                             data.setAlpha(j, i, alpha);
-//                             alpha = alpha == 255 ? 0 : 255;
-//                     }
-//                     calpha = calpha == 255 ? 0 : 255;
-//             }
-//             return new Image(device, data);
-//     }
-
-       public static boolean mnemonicMatch(String text, char key) {
-               char mnemonic = findMnemonic(text);
-               if (mnemonic == '\0')
-                       return false;
-               return Character.toUpperCase(key) == Character.toUpperCase(mnemonic);
-       }
-
-       private static char findMnemonic(String string) {
-               int index = 0;
-               int length = string.length();
-               do {
-                       while (index < length && string.charAt(index) != '&')
-                               index++;
-                       if (++index >= length)
-                               return '\0';
-                       if (string.charAt(index) != '&')
-                               return string.charAt(index);
-                       index++;
-               } while (index < length);
-               return '\0';
-       }
-       
-       public static void setFocusScrollingEnabled(Control c, boolean enabled) {
-               ScrolledComposite scomp = null;
-               
-               if (c instanceof ScrolledComposite)
-                       scomp = (ScrolledComposite)c;
-               else
-                       scomp = getScrolledComposite(c);
-               if (scomp!=null)
-                       scomp.setData(FormUtil.FOCUS_SCROLLING, enabled?null:Boolean.FALSE);
-       }
-       
-       // RAP [rh] FormUtil#setAntialias unnecessary
-//     public static void setAntialias(GC gc, int style) {
-//             if (!gc.getAdvanced()) {
-//                     gc.setAdvanced(true);
-//                     if (!gc.getAdvanced())
-//                             return;
-//             }
-//             gc.setAntialias(style);
-//     }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/IFormColors.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/IFormColors.java
deleted file mode 100644 (file)
index cf0e5d3..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms;
-
-/**
- * A place to hold all the color constants used in the forms package.
- * 
- * @since 1.0
- */
-
-public interface IFormColors {
-       /**
-        * A prefix for all the keys.
-        */
-       String PREFIX = "org.eclipse.ui.forms."; //$NON-NLS-1$
-       /**
-        * Key for the form title foreground color.
-        */
-       String TITLE = PREFIX + "TITLE"; //$NON-NLS-1$
-
-       /**
-        * A prefix for the header color constants.
-        */
-       String H_PREFIX = PREFIX + "H_"; //$NON-NLS-1$
-       /*
-        * A prefix for the section title bar color constants.
-        */
-       String TB_PREFIX = PREFIX + "TB_"; //$NON-NLS-1$        
-       /**
-        * Key for the form header background gradient ending color.
-        */
-       String H_GRADIENT_END = H_PREFIX + "GRADIENT_END"; //$NON-NLS-1$
-
-       /**
-        * Key for the form header background gradient starting color.
-        * 
-        */
-       String H_GRADIENT_START = H_PREFIX + "GRADIENT_START"; //$NON-NLS-1$
-       /**
-        * Key for the form header bottom keyline 1 color.
-        * 
-        */
-       String H_BOTTOM_KEYLINE1 = H_PREFIX + "BOTTOM_KEYLINE1"; //$NON-NLS-1$
-       /**
-        * Key for the form header bottom keyline 2 color.
-        * 
-        */
-       String H_BOTTOM_KEYLINE2 = H_PREFIX + "BOTTOM_KEYLINE2"; //$NON-NLS-1$
-       /**
-        * Key for the form header light hover color.
-        * 
-        */
-       String H_HOVER_LIGHT = H_PREFIX + "H_HOVER_LIGHT"; //$NON-NLS-1$
-       /**
-        * Key for the form header full hover color.
-        * 
-        */
-       String H_HOVER_FULL = H_PREFIX + "H_HOVER_FULL"; //$NON-NLS-1$
-
-       /**
-        * Key for the tree/table border color.
-        */
-       String BORDER = PREFIX + "BORDER"; //$NON-NLS-1$
-
-       /**
-        * Key for the section separator color.
-        */
-       String SEPARATOR = PREFIX + "SEPARATOR"; //$NON-NLS-1$
-
-       /**
-        * Key for the section title bar background.
-        */
-       String TB_BG = TB_PREFIX + "BG"; //$NON-NLS-1$
-
-       /**
-        * Key for the section title bar foreground.
-        */
-       String TB_FG = TB_PREFIX + "FG"; //$NON-NLS-1$
-
-       /**
-        * Key for the section title bar gradient.
-        * @deprecated Since 3.3, this color is not used any more. The 
-        * tool bar gradient is created starting from {@link #TB_BG} to
-        * the section background color.
-        */
-       String TB_GBG = TB_BG;
-
-       /**
-        * Key for the section title bar border.
-        */
-       String TB_BORDER = TB_PREFIX + "BORDER"; //$NON-NLS-1$
-
-       /**
-        * Key for the section toggle color. Since 3.1, this color is used for all
-        * section styles.
-        */
-       String TB_TOGGLE = TB_PREFIX + "TOGGLE"; //$NON-NLS-1$
-
-       /**
-        * Key for the section toggle hover color.
-        * 
-        */
-       String TB_TOGGLE_HOVER = TB_PREFIX + "TOGGLE_HOVER"; //$NON-NLS-1$              
-}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/IFormPart.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/IFormPart.java
deleted file mode 100644 (file)
index 954cc03..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms;
-
-/**
- * Classes that implement this interface can be added to the managed form and
- * take part in the form life cycle. The part is initialized with the form and
- * will be asked to accept focus. The part can receive form input and can elect
- * to do something according to it (for example, select an object that matches
- * the input).
- * <p>
- * The form part has two 'out of sync' states in respect to the model(s) that
- * feed the form: <b>dirty</b> and <b>stale</b>. When a part is dirty, it
- * means that the user interacted with it and now its widgets contain state that
- * is newer than the model. In order to sync up with the model, 'commit' needs
- * to be called. In contrast, the model can change 'under' the form (as a result
- * of some actions outside the form), resulting in data in the model being
- * 'newer' than the content presented in the form. A 'stale' form part is
- * brought in sync with the model by calling 'refresh'. The part is responsible
- * for notifying the form when one of these states change in the part. The form
- * reserves the right to handle this notification in the most appropriate way
- * for the situation (for example, if the form is in a page of the multi-page
- * editor, it may do nothing for stale parts if the page is currently not
- * showing).
- * <p>
- * When the form is disposed, each registered part is disposed as well. Parts
- * are responsible for releasing any system resources they created and for
- * removing themselves as listeners from all event providers.
- * 
- * @see IManagedForm
- * @since 1.0
- * 
- */
-public interface IFormPart {
-       /**
-        * Initializes the part.
-        * 
-        * @param form
-        *            the managed form that manages the part
-        */
-       void initialize(IManagedForm form);
-
-       /**
-        * Disposes the part allowing it to release allocated resources.
-        */
-       void dispose();
-
-       /**
-        * Returns true if the part has been modified with respect to the data
-        * loaded from the model.
-        * 
-        * @return true if the part has been modified with respect to the data
-        *         loaded from the model
-        */
-       boolean isDirty();
-
-       /**
-        * If part is displaying information loaded from a model, this method
-        * instructs it to commit the new (modified) data back into the model.
-        * 
-        * @param onSave
-        *            indicates if commit is called during 'save' operation or for
-        *            some other reason (for example, if form is contained in a
-        *            wizard or a multi-page editor and the user is about to leave
-        *            the page).
-        */
-       void commit(boolean onSave);
-
-       /**
-        * Notifies the part that an object has been set as overall form's input.
-        * The part can elect to react by revealing or selecting the object, or do
-        * nothing if not applicable.
-        * 
-        * @return <code>true</code> if the part has selected and revealed the
-        *         input object, <code>false</code> otherwise.
-        */
-       boolean setFormInput(Object input);
-
-       /**
-        * Instructs form part to transfer focus to the widget that should has focus
-        * in that part. The method can do nothing (if it has no widgets capable of
-        * accepting focus).
-        */
-       void setFocus();
-
-       /**
-        * Tests whether the form part is stale and needs refreshing. Parts can
-        * receive notification from models that will make their content stale, but
-        * may need to delay refreshing to improve performance (for example, there
-        * is no need to immediately refresh a part on a form that is current on a
-        * hidden page).
-        * <p>
-        * It is important to differentiate 'stale' and 'dirty' states. Part is
-        * 'dirty' if user interacted with its editable widgets and changed the
-        * values. In contrast, part is 'stale' when the data it presents in the
-        * widgets has been changed in the model without direct user interaction.
-        * 
-        * @return <code>true</code> if the part needs refreshing,
-        *         <code>false</code> otherwise.
-        */
-       boolean isStale();
-
-       /**
-        * Refreshes the part completely from the information freshly obtained from
-        * the model. The method will not be called if the part is not stale.
-        * Otherwise, the part is responsible for clearing the 'stale' flag after
-        * refreshing itself.
-        */
-       void refresh();
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/IManagedForm.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/IManagedForm.java
deleted file mode 100644 (file)
index 490d3a3..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms;
-
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.swt.custom.ScrolledComposite;
-//import org.eclipse.ui.forms.widgets.FormToolkit;
-//import org.eclipse.ui.forms.widgets.ScrolledForm;
-
-/**
- * Managed form wraps a form widget and adds life cycle methods for form parts.
- * A form part is a portion of the form that participates in form life cycle
- * events.
- * <p>
- * There is no 1/1 mapping between widgets and form parts. A widget like Section
- * can be a part by itself, but a number of widgets can gather around one form
- * part.
- * <p>
- * This interface should not be extended or implemented. New form instances
- * should be created using ManagedForm.
- * 
- * @see ManagedForm
- * @since 1.0
- * @noimplement This interface is not intended to be implemented by clients.
- * @noextend This interface is not intended to be extended by clients.
- */
-public interface IManagedForm {
-       /**
-        * Initializes the form by looping through the managed parts and
-        * initializing them. Has no effect if already called once.
-        */
-       public void initialize();
-
-       /**
-        * Returns the toolkit used by this form.
-        * 
-        * @return the toolkit
-        */
-       public FormToolkit getToolkit();
-
-       /**
-        * Returns the form widget managed by this form.
-        * 
-        * @return the form widget
-        */
-       public ScrolledComposite getForm();
-
-       /**
-        * Reflows the form as a result of the layout change.
-        * 
-        * @param changed
-        *            if <code>true</code>, discard cached layout information
-        */
-       public void reflow(boolean changed);
-
-       /**
-        * A part can use this method to notify other parts that implement
-        * IPartSelectionListener about selection changes.
-        * 
-        * @param part
-        *            the part that broadcasts the selection
-        * @param selection
-        *            the selection in the part
-        */
-       public void fireSelectionChanged(IFormPart part, ISelection selection);
-
-       /**
-        * Returns all the parts currently managed by this form.
-        * 
-        * @return the managed parts
-        */
-       IFormPart[] getParts();
-
-       /**
-        * Adds the new part to the form.
-        * 
-        * @param part
-        *            the part to add
-        */
-       void addPart(IFormPart part);
-
-       /**
-        * Removes the part from the form.
-        * 
-        * @param part
-        *            the part to remove
-        */
-       void removePart(IFormPart part);
-
-       /**
-        * Sets the input of this page to the provided object.
-        * 
-        * @param input
-        *            the new page input
-        * @return <code>true</code> if the form contains this object,
-        *         <code>false</code> otherwise.
-        */
-       boolean setInput(Object input);
-
-       /**
-        * Returns the current page input.
-        * 
-        * @return page input object or <code>null</code> if not applicable.
-        */
-       Object getInput();
-
-       /**
-        * Tests if form is dirty. A managed form is dirty if at least one managed
-        * part is dirty.
-        * 
-        * @return <code>true</code> if at least one managed part is dirty,
-        *         <code>false</code> otherwise.
-        */
-       boolean isDirty();
-
-       /**
-        * Notifies the form that the dirty state of one of its parts has changed.
-        * The global dirty state of the form can be obtained by calling 'isDirty'.
-        * 
-        * @see #isDirty
-        */
-       void dirtyStateChanged();
-
-       /**
-        * Commits the dirty form. All pending changes in the widgets are flushed
-        * into the model.
-        * 
-        * @param onSave
-        */
-       void commit(boolean onSave);
-
-       /**
-        * Tests if form is stale. A managed form is stale if at least one managed
-        * part is stale. This can happen when the underlying model changes,
-        * resulting in the presentation of the part being out of sync with the
-        * model and needing refreshing.
-        * 
-        * @return <code>true</code> if the form is stale, <code>false</code>
-        *         otherwise.
-        */
-       boolean isStale();
-
-       /**
-        * Notifies the form that the stale state of one of its parts has changed.
-        * The global stale state of the form can be obtained by calling 'isStale'.
-        */
-       void staleStateChanged();
-
-       /**
-        * Refreshes the form by refreshing every part that is stale.
-        */
-       void refresh();
-
-       /**
-        * Sets the container that owns this form. Depending on the context, the
-        * container may be wizard, editor page, editor etc.
-        * 
-        * @param container
-        *            the container of this form
-        */
-       void setContainer(Object container);
-
-       /**
-        * Returns the container of this form.
-        * 
-        * @return the form container
-        */
-       Object getContainer();
-
-       /**
-        * Returns the message manager that will keep track of messages in this
-        * form.
-        * 
-        * @return the message manager instance
-        */
-//     IMessageManager getMessageManager();
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/IPartSelectionListener.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/IPartSelectionListener.java
deleted file mode 100644 (file)
index 0f557d4..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms;
-
-import org.eclipse.jface.viewers.ISelection;
-
-/**
- * Form parts can implement this interface if they want to be 
- * notified when another part on the same form changes selection 
- * state.
- * 
- * @see IFormPart
- * @since 1.0
- */
-public interface IPartSelectionListener {
-       /**
-        * Called when the provided part has changed selection state.
-        * 
-        * @param part
-        *            the selection source
-        * @param selection
-        *            the new selection
-        */
-       public void selectionChanged(IFormPart part, ISelection selection);
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/ManagedForm.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/ManagedForm.java
deleted file mode 100644 (file)
index 4140465..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms;
-
-import java.util.Vector;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.widgets.Composite;
-//import org.eclipse.ui.forms.widgets.FormToolkit;
-//import org.eclipse.ui.forms.widgets.ScrolledForm;
-
-/**
- * Managed form wraps a form widget and adds life cycle methods for form parts.
- * A form part is a portion of the form that participates in form life cycle
- * events.
- * <p>
- * There is requirement for 1/1 mapping between widgets and form parts. A widget
- * like Section can be a part by itself, but a number of widgets can join around
- * one form part.
- * <p>
- * Note to developers: this class is left public to allow its use beyond the
- * original intention (inside a multi-page editor's page). You should limit the
- * use of this class to make new instances inside a form container (wizard page,
- * dialog etc.). Clients that need access to the class should not do it
- * directly. Instead, they should do it through IManagedForm interface as much
- * as possible.
- * 
- * @since 1.0
- */
-public class ManagedForm implements IManagedForm {
-       private Object input;
-
-       private ScrolledComposite form;
-
-       private FormToolkit toolkit;
-
-       private Object container;
-
-       private boolean ownsToolkit;
-
-       private boolean initialized;
-
-       private Vector parts = new Vector();
-
-       /**
-        * Creates a managed form in the provided parent. Form toolkit and widget
-        * will be created and owned by this object.
-        * 
-        * @param parent
-        *            the parent widget
-        */
-       public ManagedForm(Composite parent) {
-               toolkit = new FormToolkit(parent.getDisplay());
-               ownsToolkit = true;
-               form = toolkit.createScrolledForm(parent);
-               
-       }
-
-       /**
-        * Creates a managed form that will use the provided toolkit and
-        * 
-        * @param toolkit
-        * @param form
-        */
-       public ManagedForm(FormToolkit toolkit, ScrolledComposite form) {
-               this.form = form;
-               this.toolkit = toolkit;
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#addPart(org.eclipse.ui.forms.IFormPart)
-        */
-       public void addPart(IFormPart part) {
-               parts.add(part);
-               part.initialize(this);
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#removePart(org.eclipse.ui.forms.IFormPart)
-        */
-       public void removePart(IFormPart part) {
-               parts.remove(part);
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#getParts()
-        */
-       public IFormPart[] getParts() {
-               return (IFormPart[]) parts.toArray(new IFormPart[parts.size()]);
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#getToolkit()
-        */
-       public FormToolkit getToolkit() {
-               return toolkit;
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#getForm()
-        */
-       public ScrolledComposite getForm() {
-               return form;
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#reflow(boolean)
-        */
-       public void reflow(boolean changed) {
-//             form.reflow(changed);
-       }
-
-       /**
-        * A part can use this method to notify other parts that implement
-        * IPartSelectionListener about selection changes.
-        * 
-        * @param part
-        *            the part that broadcasts the selection
-        * @param selection
-        *            the selection in the part
-        * @see IPartSelectionListener
-        */
-       public void fireSelectionChanged(IFormPart part, ISelection selection) {
-               for (int i = 0; i < parts.size(); i++) {
-                       IFormPart cpart = (IFormPart) parts.get(i);
-                       if (part.equals(cpart))
-                               continue;
-//                     if (cpart instanceof IPartSelectionListener) {
-//                             ((IPartSelectionListener) cpart).selectionChanged(part,
-//                                             selection);
-//                     }
-               }
-       }
-
-       /**
-        * Initializes the form by looping through the managed parts and
-        * initializing them. Has no effect if already called once.
-        */
-       public void initialize() {
-               if (initialized)
-                       return;
-               for (int i = 0; i < parts.size(); i++) {
-                       IFormPart part = (IFormPart) parts.get(i);
-                       part.initialize(this);
-               }
-               initialized = true;
-       }
-
-       /**
-        * Disposes all the parts in this form.
-        */
-       public void dispose() {
-               for (int i = 0; i < parts.size(); i++) {
-                       IFormPart part = (IFormPart) parts.get(i);
-                       part.dispose();
-               }
-               if (ownsToolkit) {
-                       toolkit.dispose();
-               }
-       }
-
-       /**
-        * Refreshes the form by refreshes all the stale parts. Since 3.1, this
-        * method is performed on a UI thread when called from another thread so it
-        * is not needed to wrap the call in <code>Display.syncExec</code> or
-        * <code>asyncExec</code>.
-        */
-       public void refresh() {
-               Thread t = Thread.currentThread();
-               Thread dt = toolkit.getColors().getDisplay().getThread();
-               if (t.equals(dt))
-                       doRefresh();
-               else {
-                       toolkit.getColors().getDisplay().asyncExec(new Runnable() {
-                               public void run() {
-                                       doRefresh();
-                               }
-                       });
-               }
-       }
-
-       private void doRefresh() {
-               int nrefreshed = 0;
-               for (int i = 0; i < parts.size(); i++) {
-                       IFormPart part = (IFormPart) parts.get(i);
-                       if (part.isStale()) {
-                               part.refresh();
-                               nrefreshed++;
-                       }
-               }
-//             if (nrefreshed > 0)
-//                     form.reflow(true);
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#commit(boolean)
-        */
-       public void commit(boolean onSave) {
-               for (int i = 0; i < parts.size(); i++) {
-                       IFormPart part = (IFormPart) parts.get(i);
-                       if (part.isDirty())
-                               part.commit(onSave);
-               }
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#setInput(java.lang.Object)
-        */
-       public boolean setInput(Object input) {
-               boolean pageResult = false;
-
-               this.input = input;
-               for (int i = 0; i < parts.size(); i++) {
-                       IFormPart part = (IFormPart) parts.get(i);
-                       boolean result = part.setFormInput(input);
-                       if (result)
-                               pageResult = true;
-               }
-               return pageResult;
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#getInput()
-        */
-       public Object getInput() {
-               return input;
-       }
-
-       /**
-        * Transfers the focus to the first form part.
-        */
-       public void setFocus() {
-               if (parts.size() > 0) {
-                       IFormPart part = (IFormPart) parts.get(0);
-                       part.setFocus();
-               }
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#isDirty()
-        */
-       public boolean isDirty() {
-               for (int i = 0; i < parts.size(); i++) {
-                       IFormPart part = (IFormPart) parts.get(i);
-                       if (part.isDirty())
-                               return true;
-               }
-               return false;
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#isStale()
-        */
-       public boolean isStale() {
-               for (int i = 0; i < parts.size(); i++) {
-                       IFormPart part = (IFormPart) parts.get(i);
-                       if (part.isStale())
-                               return true;
-               }
-               return false;
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#dirtyStateChanged()
-        */
-       public void dirtyStateChanged() {
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#staleStateChanged()
-        */
-       public void staleStateChanged() {
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#getContainer()
-        */
-       public Object getContainer() {
-               return container;
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see org.eclipse.ui.forms.IManagedForm#setContainer(java.lang.Object)
-        */
-       public void setContainer(Object container) {
-               this.container = container;
-       }
-
-       /* (non-Javadoc)
-        * @see org.eclipse.ui.forms.IManagedForm#getMessageManager()
-        */
-//     public IMessageManager getMessageManager() {
-//             return form.getMessageManager();
-//     }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/editor/FormEditor.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/editor/FormEditor.java
deleted file mode 100644 (file)
index 484dae8..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms.editor;
-
-import org.argeo.cms.ui.eclipse.forms.FormToolkit;
-import org.eclipse.jface.dialogs.IPageChangeProvider;
-
-/**
- * This class forms a base of multi-page form editors that typically use one or
- * more pages with forms and one page for raw source of the editor input.
- * <p>
- * Pages are added 'lazily' i.e. adding a page reserves a tab for it but does
- * not cause the page control to be created. Page control is created when an
- * attempt is made to select the page in question. This allows editors with
- * several tabs and complex pages to open quickly.
- * <p>
- * Subclasses should extend this class and implement <code>addPages</code>
- * method. One of the two <code>addPage</code> methods should be called to
- * contribute pages to the editor. One adds complete (standalone) editors as
- * nested tabs. These editors will be created right away and will be hooked so
- * that key bindings, selection service etc. is compatible with the one for the
- * standalone case. The other method adds classes that implement
- * <code>IFormPage</code> interface. These pages will be created lazily and
- * they will share the common key binding and selection service. Since 3.1,
- * FormEditor is a page change provider. It allows listeners to attach to it and
- * get notified when pages are changed. This new API in JFace allows dynamic
- * help to update on page changes.
- * 
- * @since 1.0
- */
-// RAP [if] As RAP is still using workbench 3.4, the implementation of
-// IPageChangeProvider is missing from MultiPageEditorPart. Remove this code
-// with the adoption of workbench > 3.5
-//public abstract class FormEditor extends MultiPageEditorPart  {
-public abstract class FormEditor  implements
-        IPageChangeProvider {
-       private FormToolkit formToolkit;
-       
-       
-public FormToolkit getToolkit() {
-               return formToolkit;
-       }
-
-public void editorDirtyStateChanged() {
-       
-}
-
-public FormPage getActivePageInstance() {
-       return null;
-}
-
-       // RAP [if] As RAP is still using workbench 3.4, the implementation of
-// IPageChangeProvider is missing from MultiPageEditorPart. Remove this code
-// with the adoption of workbench > 3.5
-//     private ListenerList pageListeners = new ListenerList();
-//     
-//    /*
-//     * (non-Javadoc)
-//     * 
-//     * @see org.eclipse.jface.dialogs.IPageChangeProvider#addPageChangedListener(org.eclipse.jface.dialogs.IPageChangedListener)
-//     */
-//    public void addPageChangedListener(IPageChangedListener listener) {
-//        pageListeners.add(listener);
-//    }
-//
-//    /*
-//     * (non-Javadoc)
-//     * 
-//     * @see org.eclipse.jface.dialogs.IPageChangeProvider#removePageChangedListener(org.eclipse.jface.dialogs.IPageChangedListener)
-//     */
-//    public void removePageChangedListener(IPageChangedListener listener) {
-//        pageListeners.remove(listener);
-//    }
-//    
-//     private void firePageChanged(final PageChangedEvent event) {
-//        Object[] listeners = pageListeners.getListeners();
-//        for (int i = 0; i < listeners.length; ++i) {
-//            final IPageChangedListener l = (IPageChangedListener) listeners[i];
-//            SafeRunnable.run(new SafeRunnable() {
-//                public void run() {
-//                    l.pageChanged(event);
-//                }
-//            });
-//        }
-//    }
-// RAPEND [if]
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/editor/FormPage.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/editor/FormPage.java
deleted file mode 100644 (file)
index a788412..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms.editor;
-import org.argeo.cms.ui.eclipse.forms.IManagedForm;
-import org.argeo.cms.ui.eclipse.forms.ManagedForm;
-import org.eclipse.swt.custom.BusyIndicator;
-import org.eclipse.swt.custom.ScrolledComposite;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-/**
- * A base class that all pages that should be added to FormEditor must subclass.
- * Form page has an instance of PageForm that extends managed form. Subclasses
- * should override method 'createFormContent(ManagedForm)' to fill the form with
- * content. Note that page itself can be loaded lazily (on first open).
- * Consequently, the call to create the form content can come after the editor
- * has been opened for a while (in fact, it is possible to open and close the
- * editor and never create the form because no attempt has been made to show the
- * page).
- * 
- * @since 1.0
- */
-public class FormPage implements IFormPage {
-       private FormEditor editor;
-       private PageForm mform;
-       private int index;
-       private String id;
-       
-       private String partName;
-       
-       
-       
-       public void setPartName(String partName) {
-               this.partName = partName;
-       }
-       private static class PageForm extends ManagedForm {
-               public PageForm(FormPage page, ScrolledComposite form) {
-                       super(page.getEditor().getToolkit(), form);
-                       setContainer(page);
-               }
-               
-               public FormPage getPage() {
-                       return (FormPage)getContainer();
-               }
-               public void dirtyStateChanged() {
-                       getPage().getEditor().editorDirtyStateChanged();
-               }
-               public void staleStateChanged() {
-                       if (getPage().isActive())
-                               refresh();
-               }
-       }
-       /**
-        * A constructor that creates the page and initializes it with the editor.
-        * 
-        * @param editor
-        *            the parent editor
-        * @param id
-        *            the unique identifier
-        * @param title
-        *            the page title
-        */
-       public FormPage(FormEditor editor, String id, String title) {
-               this(id, title);
-               initialize(editor);
-       }
-       /**
-        * The constructor. The parent editor need to be passed in the
-        * <code>initialize</code> method if this constructor is used.
-        * 
-        * @param id
-        *            a unique page identifier
-        * @param title
-        *            a user-friendly page title
-        */
-       public FormPage(String id, String title) {
-               this.id = id;
-               setPartName(title);
-       }
-       /**
-        * Initializes the form page.
-        * 
-        * @see IEditorPart#init
-        */
-//     public void init(IEditorSite site, IEditorInput input) {
-//             setSite(site);
-//             setInput(input);
-//     }
-       /**
-        * Primes the form page with the parent editor instance.
-        * 
-        * @param editor
-        *            the parent editor
-        */
-       public void initialize(FormEditor editor) {
-               this.editor = editor;
-       }
-       /**
-        * Returns the parent editor.
-        * 
-        * @return parent editor instance
-        */
-       public FormEditor getEditor() {
-               return editor;
-       }
-       /**
-        * Returns the managed form owned by this page.
-        * 
-        * @return the managed form
-        */
-       public IManagedForm getManagedForm() {
-               return mform;
-       }
-       /**
-        * Implements the required method by refreshing the form when set active.
-        * Subclasses must call super when overriding this method.
-        */
-       public void setActive(boolean active) {
-               if (active) {
-                       // We are switching to this page - refresh it
-                       // if needed.
-                       if (mform != null)
-                               mform.refresh();
-               }
-       }
-       /**
-        * Tests if the page is active by asking the parent editor if this page is
-        * the currently active page.
-        * 
-        * @return <code>true</code> if the page is currently active,
-        *         <code>false</code> otherwise.
-        */
-       public boolean isActive() {
-               return this.equals(editor.getActivePageInstance());
-       }
-       /**
-        * Creates the part control by creating the managed form using the parent
-        * editor's toolkit. Subclasses should override
-        * <code>createFormContent(IManagedForm)</code> to populate the form with
-        * content.
-        * 
-        * @param parent
-        *            the page parent composite
-        */
-       public void createPartControl(Composite parent) {
-               ScrolledComposite form = editor.getToolkit().createScrolledForm(parent);
-               mform = new PageForm(this, form);
-               BusyIndicator.showWhile(parent.getDisplay(), new Runnable() {
-                       public void run() {
-                               createFormContent(mform);
-                       }
-               });
-       }
-       /**
-        * Subclasses should override this method to create content in the form
-        * hosted in this page.
-        * 
-        * @param managedForm
-        *            the form hosted in this page.
-        */
-       protected void createFormContent(IManagedForm managedForm) {
-       }
-       /**
-        * Returns the form page control.
-        * 
-        * @return managed form's control
-        */
-       public Control getPartControl() {
-               return mform != null ? mform.getForm() : null;
-       }
-       /**
-        * Disposes the managed form.
-        */
-       public void dispose() {
-               if (mform != null)
-                       mform.dispose();
-       }
-       /**
-        * Returns the unique identifier that can be used to reference this page.
-        * 
-        * @return the unique page identifier
-        */
-       public String getId() {
-               return id;
-       }
-       /**
-        * Returns <code>null</code>- form page has no title image. Subclasses
-        * may override.
-        * 
-        * @return <code>null</code>
-        */
-       public Image getTitleImage() {
-               return null;
-       }
-       /**
-        * Sets the focus by delegating to the managed form.
-        */
-       public void setFocus() {
-               if (mform != null)
-                       mform.setFocus();
-       }
-       /**
-        * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
-        */
-//     public void doSave(IProgressMonitor monitor) {
-//             if (mform != null)
-//                     mform.commit(true);
-//     }
-       /**
-        * @see org.eclipse.ui.ISaveablePart#doSaveAs()
-        */
-       public void doSaveAs() {
-       }
-       /**
-        * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
-        */
-       public boolean isSaveAsAllowed() {
-               return false;
-       }
-       /**
-        * Implemented by testing if the managed form is dirty.
-        * 
-        * @return <code>true</code> if the managed form is dirty,
-        *         <code>false</code> otherwise.
-        * 
-        * @see org.eclipse.ui.ISaveablePart#isDirty()
-        */
-       public boolean isDirty() {
-               return mform != null ? mform.isDirty() : false;
-       }
-       /**
-        * Preserves the page index.
-        * 
-        * @param index
-        *            the assigned page index
-        */
-       public void setIndex(int index) {
-               this.index = index;
-       }
-       /**
-        * Returns the saved page index.
-        * 
-        * @return the page index
-        */
-       public int getIndex() {
-               return index;
-       }
-       /**
-        * Form pages are not editors.
-        * 
-        * @return <code>false</code>
-        */
-       public boolean isEditor() {
-               return false;
-       }
-       /**
-        * Attempts to select and reveal the given object by passing the request to
-        * the managed form.
-        * 
-        * @param object
-        *            the object to select and reveal in the page if possible.
-        * @return <code>true</code> if the page has been successfully selected
-        *         and revealed by one of the managed form parts, <code>false</code>
-        *         otherwise.
-        */
-       public boolean selectReveal(Object object) {
-               if (mform != null)
-                       return mform.setInput(object);
-               return false;
-       }
-       /**
-        * By default, editor will be allowed to flip the page.
-        * @return <code>true</code>
-        */
-       public boolean canLeaveThePage() {
-               return true;
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/editor/IFormPage.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/eclipse/forms/editor/IFormPage.java
deleted file mode 100644 (file)
index eb08cb5..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-package org.argeo.cms.ui.eclipse.forms.editor;
-import org.argeo.cms.ui.eclipse.forms.IManagedForm;
-import org.eclipse.swt.widgets.Control;
-/**
- * Interface that all GUI pages need to implement in order
- * to be added to FormEditor part. The interface makes 
- * several assumptions:
- * <ul>
- * <li>The form page has a managed form</li>
- * <li>The form page has a unique id</li>
- * <li>The form page can be GUI but can also wrap a complete
- * editor class (in that case, it should return <code>true</code>
- * from <code>isEditor()</code> method).</li>
- * <li>The form page is lazy i.e. understands that 
- * its part control will be created at the last possible
- * moment.</li>.
- * </ul>
- * <p>Existing editors can be wrapped by implementing
- * this interface. In this case, 'isEditor' should return <code>true</code>.
- * A common editor to wrap in <code>TextEditor</code> that is
- * often added to show the raw source code of the file open into
- * the multi-page editor.
- * 
- * @since 1.0
- */
-public interface IFormPage {
-       /**
-        * @param editor
-        *            the form editor that this page belongs to
-        */
-       void initialize(FormEditor editor);
-       /**
-        * Returns the editor this page belongs to.
-        * 
-        * @return the form editor
-        */
-       FormEditor getEditor();
-       /**
-        * Returns the managed form of this page, unless this is a source page.
-        * 
-        * @return the managed form or <samp>null </samp> if this is a source page.
-        */
-       IManagedForm getManagedForm();
-       /**
-        * Indicates whether the page has become the active in the editor. Classes
-        * that implement this interface may use this method to commit the page (on
-        * <code>false</code>) or lazily create and/or populate the content on
-        * <code>true</code>.
-        * 
-        * @param active
-        *            <code>true</code> if page should be visible, <code>false</code>
-        *            otherwise.
-        */
-       void setActive(boolean active);
-       /**
-        * Returns <samp>true </samp> if page is currently active, false if not.
-        * 
-        * @return <samp>true </samp> for active page.
-        */
-       boolean isActive();
-       /**
-        * Tests if the content of the page is in a state that allows the
-        * editor to flip to another page. Typically, pages that contain
-        * raw source with syntax errors should not allow editors to 
-        * leave them until errors are corrected.
-        * @return <code>true</code> if the editor can flip to another page,
-        * <code>false</code> otherwise.
-        */
-       boolean canLeaveThePage();
-       /**
-        * Returns the control associated with this page.
-        * 
-        * @return the control of this page if created or <samp>null </samp> if the
-        *         page has not been shown yet.
-        */
-       Control getPartControl();
-       /**
-        * Page must have a unique id that can be used to show it without knowing
-        * its relative position in the editor.
-        * 
-        * @return the unique page identifier
-        */
-       String getId();
-       /**
-        * Returns the position of the page in the editor.
-        * 
-        * @return the zero-based index of the page in the editor.
-        */
-       int getIndex();
-       /**
-        * Sets the position of the page in the editor.
-        * 
-        * @param index
-        *            the zero-based index of the page in the editor.
-        */
-       void setIndex(int index);
-       /**
-        * Tests whether this page wraps a complete editor that
-        * can be registered on its own, or represents a page
-        * that cannot exist outside the multi-page editor context.
-        * 
-        * @return <samp>true </samp> if the page wraps an editor,
-        *         <samp>false </samp> if this is a form page.
-        */
-       boolean isEditor();
-       /**
-        * A hint to bring the provided object into focus. If the object is in a
-        * tree or table control, select it. If it is shown on a scrollable page,
-        * ensure that it is visible. If the object is not presented in 
-        * the page, <code>false</code> should be returned to allow another
-        * page to try.
-        * 
-        * @param object
-        *            object to select and reveal
-        * @return <code>true</code> if the request was successful, <code>false</code>
-        *         otherwise.
-        */
-       boolean selectReveal(Object object);
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditableLink.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditableLink.java
deleted file mode 100644 (file)
index 3c1e8cd..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.argeo.cms.ui.forms;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.SwtEditablePart;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Editable String that displays a browsable link when read-only */
-public class EditableLink extends EditablePropertyString implements
-               SwtEditablePart {
-       private static final long serialVersionUID = 5055000749992803591L;
-
-       private String type;
-       private String message;
-       private boolean readOnly;
-
-       public EditableLink(Composite parent, int style, Node node,
-                       String propertyName, String type, String message)
-                       throws RepositoryException {
-               super(parent, style, node, propertyName, message);
-               this.message = message;
-               this.type = type;
-
-               readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
-               if (node.hasProperty(propertyName)) {
-                       this.setStyle(FormStyle.propertyText.style());
-                       this.setText(node.getProperty(propertyName).getString());
-               } else {
-                       this.setStyle(FormStyle.propertyMessage.style());
-                       this.setText("");
-               }
-       }
-
-       public void setText(String text) {
-               Control child = getControl();
-               if (child instanceof Label) {
-                       Label lbl = (Label) child;
-                       if (EclipseUiUtils.isEmpty(text))
-                               lbl.setText(message);
-                       else if (readOnly)
-                               setLinkValue(lbl, text);
-                       else
-                               // if canEdit() we put only the value with no link
-                               // to avoid glitches of the edition life cycle
-                               lbl.setText(text);
-               } else if (child instanceof Text) {
-                       Text txt = (Text) child;
-                       if (EclipseUiUtils.isEmpty(text)) {
-                               txt.setText("");
-                               txt.setMessage(message);
-                       } else
-                               txt.setText(text);
-               }
-       }
-
-       private void setLinkValue(Label lbl, String text) {
-               if (FormStyle.email.style().equals(type))
-                       lbl.setText(FormUtils.getMailLink(text));
-               else if (FormStyle.phone.style().equals(type))
-                       lbl.setText(FormUtils.getPhoneLink(text));
-               else if (FormStyle.website.style().equals(type))
-                       lbl.setText(FormUtils.getUrlLink(text));
-               else if (FormStyle.facebook.style().equals(type)
-                               || FormStyle.instagram.style().equals(type)
-                               || FormStyle.linkedIn.style().equals(type)
-                               || FormStyle.twitter.style().equals(type))
-                       lbl.setText(FormUtils.getUrlLink(text));
-       }
-}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditableMultiStringProperty.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditableMultiStringProperty.java
deleted file mode 100644 (file)
index ff82700..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-package org.argeo.cms.ui.forms;
-
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.SwtEditablePart;
-import org.argeo.cms.ui.widgets.StyledControl;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.events.TraverseEvent;
-import org.eclipse.swt.events.TraverseListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Display, add or remove values from a list in a CMS context */
-public class EditableMultiStringProperty extends StyledControl implements SwtEditablePart {
-       private static final long serialVersionUID = -7044614381252178595L;
-
-       private String propertyName;
-       private String message;
-       // TODO implement the ability to provide a list of possible values
-//     private String[] possibleValues;
-       private boolean canEdit;
-       private SelectionListener removeValueSL;
-       private List<String> values;
-
-       // TODO manage within the CSS
-       private int rowSpacing = 5;
-       private int rowMarging = 0;
-       private int oneValueMargingRight = 5;
-       private int btnWidth = 16;
-       private int btnHeight = 16;
-       private int btnHorizontalIndent = 3;
-
-       public EditableMultiStringProperty(Composite parent, int style, Node node, String propertyName, List<String> values,
-                       String[] possibleValues, String addValueMsg, SelectionListener removeValueSelectionListener)
-                       throws RepositoryException {
-               super(parent, style, node, true);
-
-               this.propertyName = propertyName;
-               this.values = values;
-//             this.possibleValues = new String[] { "Un", "Deux", "Trois" };
-               this.message = addValueMsg;
-               this.canEdit = removeValueSelectionListener != null;
-               this.removeValueSL = removeValueSelectionListener;
-       }
-
-       public List<String> getValues() {
-               return values;
-       }
-
-       public void setValues(List<String> values) {
-               this.values = values;
-       }
-
-       // Row layout items do not need explicit layout data
-       protected void setControlLayoutData(Control control) {
-       }
-
-       /** To be overridden */
-       protected void setContainerLayoutData(Composite composite) {
-               composite.setLayoutData(CmsSwtUtils.fillWidth());
-       }
-
-       @Override
-       public Control getControl() {
-               return super.getControl();
-       }
-
-       @Override
-       protected Control createControl(Composite box, String style) {
-               Composite row = new Composite(box, SWT.NO_FOCUS);
-               row.setLayoutData(EclipseUiUtils.fillAll());
-
-               RowLayout rl = new RowLayout(SWT.HORIZONTAL);
-               rl.wrap = true;
-               rl.spacing = rowSpacing;
-               rl.marginRight = rl.marginLeft = rl.marginBottom = rl.marginTop = rowMarging;
-               row.setLayout(rl);
-
-               if (values != null) {
-                       for (final String value : values) {
-                               if (canEdit)
-                                       createRemovableValue(row, SWT.SINGLE, value);
-                               else
-                                       createValueLabel(row, SWT.SINGLE, value);
-                       }
-               }
-
-               if (!canEdit)
-                       return row;
-               else if (isEditing())
-                       return createText(row, style);
-               else
-                       return createLabel(row, style);
-       }
-
-       /**
-        * Override to provide specific layout for the existing values, typically adding
-        * a pound (#) char for tags or anchor info for browsable links. We assume the
-        * parent composite already has a layout and it is the caller responsibility to
-        * apply corresponding layout data
-        */
-       protected Label createValueLabel(Composite parent, int style, String value) {
-               Label label = new Label(parent, style);
-               label.setText("#" + value);
-               CmsSwtUtils.markup(label);
-               CmsSwtUtils.style(label, FormStyle.propertyText.style());
-               return label;
-       }
-
-       private Composite createRemovableValue(Composite parent, int style, String value) {
-               Composite valCmp = new Composite(parent, SWT.NO_FOCUS);
-               GridLayout gl = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false));
-               gl.marginRight = oneValueMargingRight;
-               valCmp.setLayout(gl);
-
-               createValueLabel(valCmp, SWT.WRAP, value);
-
-               Button deleteBtn = new Button(valCmp, SWT.FLAT);
-               deleteBtn.setData(FormConstants.LINKED_VALUE, value);
-               deleteBtn.addSelectionListener(removeValueSL);
-               CmsSwtUtils.style(deleteBtn, FormStyle.delete.style() + FormStyle.BUTTON_SUFFIX);
-               GridData gd = new GridData();
-               gd.heightHint = btnHeight;
-               gd.widthHint = btnWidth;
-               gd.horizontalIndent = btnHorizontalIndent;
-               deleteBtn.setLayoutData(gd);
-
-               return valCmp;
-       }
-
-       protected Text createText(Composite box, String style) {
-               final Text text = new Text(box, getStyle());
-               // The "add new value" text is not meant to change, so we can set it on
-               // creation
-               text.setMessage(message);
-               CmsSwtUtils.style(text, style);
-               text.setFocus();
-
-               text.addTraverseListener(new TraverseListener() {
-                       private static final long serialVersionUID = 1L;
-
-                       public void keyTraversed(TraverseEvent e) {
-                               if (e.keyCode == SWT.CR) {
-                                       addValue(text);
-                                       e.doit = false;
-                               }
-                       }
-               });
-
-               // The OK button does not work with the focusOut listener
-               // because focus out is called before the OK button is pressed
-
-               // // we must call layout() now so that the row data can compute the
-               // height
-               // // of the other controls.
-               // text.getParent().layout();
-               // int height = text.getSize().y;
-               //
-               // Button okBtn = new Button(box, SWT.BORDER | SWT.PUSH | SWT.BOTTOM);
-               // okBtn.setText("OK");
-               // RowData rd = new RowData(SWT.DEFAULT, height - 2);
-               // okBtn.setLayoutData(rd);
-               //
-               // okBtn.addSelectionListener(new SelectionAdapter() {
-               // private static final long serialVersionUID = 2780819012423622369L;
-               //
-               // @Override
-               // public void widgetSelected(SelectionEvent e) {
-               // addValue(text);
-               // }
-               // });
-
-               return text;
-       }
-
-       /** Performs the real addition, overwrite to make further sanity checks */
-       protected void addValue(Text text) {
-               String value = text.getText();
-               String errMsg = null;
-
-               if (EclipseUiUtils.isEmpty(value))
-                       return;
-
-               if (values.contains(value))
-                       errMsg = "Dupplicated value: " + value + ", please correct and try again";
-               if (errMsg != null)
-                       MessageDialog.openError(this.getShell(), "Addition not allowed", errMsg);
-               else {
-                       values.add(value);
-                       Composite newCmp = createRemovableValue(text.getParent(), SWT.SINGLE, value);
-                       newCmp.moveAbove(text);
-                       text.setText("");
-                       newCmp.getParent().layout();
-               }
-       }
-
-       protected Label createLabel(Composite box, String style) {
-               if (canEdit) {
-                       Label lbl = new Label(box, getStyle());
-                       lbl.setText(message);
-                       CmsSwtUtils.style(lbl, style);
-                       CmsSwtUtils.markup(lbl);
-                       if (mouseListener != null)
-                               lbl.addMouseListener(mouseListener);
-                       return lbl;
-               }
-               return null;
-       }
-
-       protected void clear(boolean deep) {
-               Control child = getControl();
-               if (deep)
-                       super.clear(deep);
-               else {
-                       child.getParent().dispose();
-               }
-       }
-
-       public void setText(String text) {
-               Control child = getControl();
-               if (child instanceof Label) {
-                       Label lbl = (Label) child;
-                       if (canEdit)
-                               lbl.setText(text);
-                       else
-                               lbl.setText("");
-               } else if (child instanceof Text) {
-                       Text txt = (Text) child;
-                       txt.setText(text);
-               }
-       }
-
-       public synchronized void startEditing() {
-               CmsSwtUtils.style(getControl(), FormStyle.propertyText.style());
-//             getControl().setData(STYLE, FormStyle.propertyText.style());
-               super.startEditing();
-       }
-
-       public synchronized void stopEditing() {
-               CmsSwtUtils.style(getControl(), FormStyle.propertyMessage.style());
-//             getControl().setData(STYLE, FormStyle.propertyMessage.style());
-               super.stopEditing();
-       }
-
-       public String getPropertyName() {
-               return propertyName;
-       }
-}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyDate.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyDate.java
deleted file mode 100644 (file)
index 641f916..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-package org.argeo.cms.ui.forms;
-
-import java.text.DateFormat;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.SwtEditablePart;
-import org.argeo.cms.ui.widgets.StyledControl;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.ShellAdapter;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.DateTime;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-/** CMS form part to display and edit a date */
-public class EditablePropertyDate extends StyledControl implements SwtEditablePart {
-       private static final long serialVersionUID = 2500215515778162468L;
-
-       // Context
-       private String propertyName;
-       private String message;
-       private DateFormat dateFormat;
-
-       // UI Objects
-       private Text dateTxt;
-       private Button openCalBtn;
-
-       // TODO manage within the CSS
-       private int fieldBtnSpacing = 5;
-
-       /**
-        * 
-        * @param parent
-        * @param style
-        * @param node
-        * @param propertyName
-        * @param message
-        * @param dateFormat   provide a {@link DateFormat} as contract to be able to
-        *                     read/write dates as strings
-        * @throws RepositoryException
-        */
-       public EditablePropertyDate(Composite parent, int style, Node node, String propertyName, String message,
-                       DateFormat dateFormat) throws RepositoryException {
-               super(parent, style, node, false);
-
-               this.propertyName = propertyName;
-               this.message = message;
-               this.dateFormat = dateFormat;
-
-               if (node.hasProperty(propertyName)) {
-                       this.setStyle(FormStyle.propertyText.style());
-                       this.setText(dateFormat.format(node.getProperty(propertyName).getDate().getTime()));
-               } else {
-                       this.setStyle(FormStyle.propertyMessage.style());
-                       this.setText(message);
-               }
-       }
-
-       public void setText(String text) {
-               Control child = getControl();
-               if (child instanceof Label) {
-                       Label lbl = (Label) child;
-                       if (EclipseUiUtils.isEmpty(text))
-                               lbl.setText(message);
-                       else
-                               lbl.setText(text);
-               } else if (child instanceof Text) {
-                       Text txt = (Text) child;
-                       if (EclipseUiUtils.isEmpty(text)) {
-                               txt.setText("");
-                       } else
-                               txt.setText(text);
-               }
-       }
-
-       public synchronized void startEditing() {
-               // if (dateTxt != null && !dateTxt.isDisposed())
-               CmsSwtUtils.style(getControl(), FormStyle.propertyText);
-//             getControl().setData(STYLE, FormStyle.propertyText.style());
-               super.startEditing();
-       }
-
-       public synchronized void stopEditing() {
-               if (EclipseUiUtils.isEmpty(dateTxt.getText()))
-                       CmsSwtUtils.style(getControl(), FormStyle.propertyMessage);
-//                     getControl().setData(STYLE, FormStyle.propertyMessage.style());
-               else
-                       CmsSwtUtils.style(getControl(), FormStyle.propertyText);
-//             getControl().setData(STYLE, FormStyle.propertyText.style());
-               super.stopEditing();
-       }
-
-       public String getPropertyName() {
-               return propertyName;
-       }
-
-       @Override
-       protected Control createControl(Composite box, String style) {
-               if (isEditing()) {
-                       return createCustomEditableControl(box, style);
-               } else
-                       return createLabel(box, style);
-       }
-
-       protected Label createLabel(Composite box, String style) {
-               Label lbl = new Label(box, getStyle() | SWT.WRAP);
-               lbl.setLayoutData(CmsSwtUtils.fillWidth());
-               CmsSwtUtils.style(lbl, style);
-               CmsSwtUtils.markup(lbl);
-               if (mouseListener != null)
-                       lbl.addMouseListener(mouseListener);
-               return lbl;
-       }
-
-       private Control createCustomEditableControl(Composite box, String style) {
-               box.setLayoutData(CmsSwtUtils.fillWidth());
-               Composite dateComposite = new Composite(box, SWT.NONE);
-               GridLayout gl = EclipseUiUtils.noSpaceGridLayout(new GridLayout(2, false));
-               gl.horizontalSpacing = fieldBtnSpacing;
-               dateComposite.setLayout(gl);
-               dateTxt = new Text(dateComposite, SWT.BORDER);
-               CmsSwtUtils.style(dateTxt, style);
-               dateTxt.setLayoutData(new GridData(120, SWT.DEFAULT));
-               dateTxt.setToolTipText(
-                               "Enter a date with form \"" + FormUtils.DEFAULT_SHORT_DATE_FORMAT + "\" or use the calendar");
-               openCalBtn = new Button(dateComposite, SWT.FLAT);
-               CmsSwtUtils.style(openCalBtn, FormStyle.calendar.style() + FormStyle.BUTTON_SUFFIX);
-               GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false);
-               gd.heightHint = 17;
-               openCalBtn.setLayoutData(gd);
-               // openCalBtn.setImage(PeopleRapImages.CALENDAR_BTN);
-
-               openCalBtn.addSelectionListener(new SelectionAdapter() {
-                       private static final long serialVersionUID = 1L;
-
-                       public void widgetSelected(SelectionEvent event) {
-                               CalendarPopup popup = new CalendarPopup(dateTxt);
-                               popup.open();
-                       }
-               });
-
-               // dateTxt.addFocusListener(new FocusListener() {
-               // private static final long serialVersionUID = 1L;
-               //
-               // @Override
-               // public void focusLost(FocusEvent event) {
-               // String newVal = dateTxt.getText();
-               // // Enable reset of the field
-               // if (FormUtils.notNull(newVal))
-               // calendar = null;
-               // else {
-               // try {
-               // Calendar newCal = parseDate(newVal);
-               // // DateText.this.setText(newCal);
-               // calendar = newCal;
-               // } catch (ParseException pe) {
-               // // Silent. Manage error popup?
-               // if (calendar != null)
-               // EditablePropertyDate.this.setText(calendar);
-               // }
-               // }
-               // }
-               //
-               // @Override
-               // public void focusGained(FocusEvent event) {
-               // }
-               // });
-               return dateTxt;
-       }
-
-       protected void clear(boolean deep) {
-               Control child = getControl();
-               if (deep || child instanceof Label)
-                       super.clear(deep);
-               else {
-                       child.getParent().dispose();
-               }
-       }
-
-       /** Enable setting a custom tooltip on the underlying text */
-       @Deprecated
-       public void setToolTipText(String toolTipText) {
-               dateTxt.setToolTipText(toolTipText);
-       }
-
-       @Deprecated
-       /** Enable setting a custom message on the underlying text */
-       public void setMessage(String message) {
-               dateTxt.setMessage(message);
-       }
-
-       @Deprecated
-       public void setText(Calendar cal) {
-               String newValueStr = "";
-               if (cal != null)
-                       newValueStr = dateFormat.format(cal.getTime());
-               if (!newValueStr.equals(dateTxt.getText()))
-                       dateTxt.setText(newValueStr);
-       }
-
-       // UTILITIES TO MANAGE THE CALENDAR POPUP
-       // TODO manage the popup shell in a cleaner way
-       private class CalendarPopup extends Shell {
-               private static final long serialVersionUID = 1L;
-               private DateTime dateTimeCtl;
-
-               public CalendarPopup(Control source) {
-                       super(source.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
-                       populate();
-                       // Add border and shadow style
-                       CmsSwtUtils.markup(CalendarPopup.this);
-                       CmsSwtUtils.style(CalendarPopup.this, FormStyle.popupCalendar.style());
-                       pack();
-                       layout();
-                       setLocation(source.toDisplay((source.getLocation().x - 2), (source.getSize().y) + 3));
-
-                       addShellListener(new ShellAdapter() {
-                               private static final long serialVersionUID = 5178980294808435833L;
-
-                               @Override
-                               public void shellDeactivated(ShellEvent e) {
-                                       close();
-                                       dispose();
-                               }
-                       });
-                       open();
-               }
-
-               private void setProperty() {
-                       // Direct set does not seems to work. investigate
-                       // cal.set(dateTimeCtl.getYear(), dateTimeCtl.getMonth(),
-                       // dateTimeCtl.getDay(), 12, 0);
-                       Calendar cal = new GregorianCalendar();
-                       cal.set(Calendar.YEAR, dateTimeCtl.getYear());
-                       cal.set(Calendar.MONTH, dateTimeCtl.getMonth());
-                       cal.set(Calendar.DAY_OF_MONTH, dateTimeCtl.getDay());
-                       String dateStr = dateFormat.format(cal.getTime());
-                       dateTxt.setText(dateStr);
-               }
-
-               protected void populate() {
-                       setLayout(EclipseUiUtils.noSpaceGridLayout());
-
-                       dateTimeCtl = new DateTime(this, SWT.CALENDAR);
-                       dateTimeCtl.setLayoutData(EclipseUiUtils.fillAll());
-
-                       Calendar calendar = FormUtils.parseDate(dateFormat, dateTxt.getText());
-
-                       if (calendar != null)
-                               dateTimeCtl.setDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
-                                               calendar.get(Calendar.DAY_OF_MONTH));
-
-                       dateTimeCtl.addSelectionListener(new SelectionAdapter() {
-                               private static final long serialVersionUID = -8414377364434281112L;
-
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       setProperty();
-                               }
-                       });
-
-                       dateTimeCtl.addMouseListener(new MouseListener() {
-                               private static final long serialVersionUID = 1L;
-
-                               @Override
-                               public void mouseUp(MouseEvent e) {
-                               }
-
-                               @Override
-                               public void mouseDown(MouseEvent e) {
-                               }
-
-                               @Override
-                               public void mouseDoubleClick(MouseEvent e) {
-                                       setProperty();
-                                       close();
-                                       dispose();
-                               }
-                       });
-               }
-       }
-}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyString.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyString.java
deleted file mode 100644 (file)
index f2575e1..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-package org.argeo.cms.ui.forms;
-
-import static org.argeo.cms.ui.forms.FormStyle.propertyMessage;
-import static org.argeo.cms.ui.forms.FormStyle.propertyText;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.SwtEditablePart;
-import org.argeo.cms.ui.widgets.EditableText;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Editable String in a CMS context */
-public class EditablePropertyString extends EditableText implements SwtEditablePart {
-       private static final long serialVersionUID = 5055000749992803591L;
-
-       private String propertyName;
-       private String message;
-
-       // encode the '&' character in rap
-       private final static String AMPERSAND = "&#38;";
-       private final static String AMPERSAND_REGEX = "&(?![#a-zA-Z0-9]+;)";
-
-       public EditablePropertyString(Composite parent, int style, Node node, String propertyName, String message)
-                       throws RepositoryException {
-               super(parent, style, node, true);
-               //setUseTextAsLabel(true);
-               this.propertyName = propertyName;
-               this.message = message;
-
-               if (node.hasProperty(propertyName)) {
-                       this.setStyle(propertyText.style());
-                       this.setText(node.getProperty(propertyName).getString());
-               } else {
-                       this.setStyle(propertyMessage.style());
-                       this.setText(message + "  ");
-               }
-       }
-
-       public void setText(String text) {
-               Control child = getControl();
-               if (child instanceof Label) {
-                       Label lbl = (Label) child;
-                       if (EclipseUiUtils.isEmpty(text))
-                               lbl.setText(message + "  ");
-                       else
-                               // TODO enhance this
-                               lbl.setText(text.replaceAll(AMPERSAND_REGEX, AMPERSAND));
-               } else if (child instanceof Text) {
-                       Text txt = (Text) child;
-                       if (EclipseUiUtils.isEmpty(text)) {
-                               txt.setText("");
-                               txt.setMessage(message + " ");
-                       } else
-                               txt.setText(text.replaceAll("<br/>", "\n"));
-               }
-       }
-
-       public synchronized void startEditing() {
-               CmsSwtUtils.style(getControl(), FormStyle.propertyText);
-               super.startEditing();
-       }
-
-       public synchronized void stopEditing() {
-               if (EclipseUiUtils.isEmpty(((Text) getControl()).getText()))
-                       CmsSwtUtils.style(getControl(), FormStyle.propertyMessage);
-               else
-                       CmsSwtUtils.style(getControl(), FormStyle.propertyText);
-               super.stopEditing();
-       }
-
-       public String getPropertyName() {
-               return propertyName;
-       }
-}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormConstants.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormConstants.java
deleted file mode 100644 (file)
index fe9f7e7..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.argeo.cms.ui.forms;
-
-/** Constants used in the various CMS Forms */
-public interface FormConstants {
-       // DATAKEYS
-       public final static String LINKED_VALUE = "LinkedValue";
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormEditorHeader.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormEditorHeader.java
deleted file mode 100644 (file)
index a75c191..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-package org.argeo.cms.ui.forms;
-
-import java.util.Observable;
-import java.util.Observer;
-
-import javax.jcr.Node;
-
-import org.argeo.api.cms.ux.CmsEditable;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-
-/** Add life cycle management abilities to an editable form page */
-public class FormEditorHeader implements SelectionListener, Observer {
-       private static final long serialVersionUID = 7392898696542484282L;
-
-       // private final Node context;
-       private final CmsEditable cmsEditable;
-       private Button publishBtn;
-
-       // Should we provide here the ability to switch from read only to edition
-       // mode?
-       // private Button editBtn;
-       // private boolean readOnly;
-
-       // TODO add information about the current node status, typically if it is
-       // dirty or not
-
-       private Composite parent;
-       private Composite display;
-       private Object layoutData;
-
-       public FormEditorHeader(Composite parent, int style, Node context,
-                       CmsEditable cmsEditable) {
-               this.cmsEditable = cmsEditable;
-               this.parent = parent;
-               // readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
-               // this.context = context;
-               if (this.cmsEditable instanceof Observable)
-                       ((Observable) this.cmsEditable).addObserver(this);
-               refresh();
-       }
-
-       public void setLayoutData(Object layoutData) {
-               this.layoutData = layoutData;
-               if (display != null && !display.isDisposed())
-                       display.setLayoutData(layoutData);
-       }
-
-       protected void refresh() {
-               if (display != null && !display.isDisposed())
-                       display.dispose();
-
-               display = new Composite(parent, SWT.NONE);
-               display.setLayoutData(layoutData);
-
-               CmsSwtUtils.style(display, FormStyle.header.style());
-               display.setBackgroundMode(SWT.INHERIT_FORCE);
-
-               display.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
-               publishBtn = createSimpleBtn(display, getPublishButtonLabel());
-               display.moveAbove(null);
-               parent.layout();
-       }
-
-       private Button createSimpleBtn(Composite parent, String label) {
-               Button button = new Button(parent, SWT.FLAT | SWT.PUSH);
-               button.setText(label);
-               CmsSwtUtils.style(button, FormStyle.header.style());
-               button.addSelectionListener(this);
-               return button;
-       }
-
-       private String getPublishButtonLabel() {
-               // Rather check if the current node differs from what has been
-               // previously committed
-               // For the time being, we always reach here, the underlying CmsEditable
-               // is always editing.
-               if (cmsEditable.isEditing())
-                       return " Publish ";
-               else
-                       return " Edit ";
-       }
-
-       @Override
-       public void widgetSelected(SelectionEvent e) {
-               if (e.getSource() == publishBtn) {
-                       // For the time being, the underlying CmsEditable
-                       // is always editing when we reach this point
-                       if (cmsEditable.isEditing()) {
-                               // we always leave the node in a check outed state
-                               cmsEditable.stopEditing();
-                               cmsEditable.startEditing();
-                       } else {
-                               cmsEditable.startEditing();
-                       }
-               }
-       }
-
-       @Override
-       public void widgetDefaultSelected(SelectionEvent e) {
-       }
-
-       @Override
-       public void update(Observable o, Object arg) {
-               if (o == cmsEditable) {
-                       refresh();
-               }
-       }
-}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormPageViewer.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormPageViewer.java
deleted file mode 100644 (file)
index 1888055..0000000
+++ /dev/null
@@ -1,608 +0,0 @@
-package org.argeo.cms.ui.forms;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.ValueFormatException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.Cms2DSize;
-import org.argeo.api.cms.ux.CmsEditable;
-import org.argeo.api.cms.ux.CmsImageManager;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.SwtEditablePart;
-import org.argeo.cms.ui.viewers.AbstractPageViewer;
-import org.argeo.cms.ui.viewers.Section;
-import org.argeo.cms.ui.viewers.SectionPart;
-import org.argeo.cms.ui.widgets.EditableImage;
-import org.argeo.cms.ui.widgets.Img;
-import org.argeo.cms.ui.widgets.StyledControl;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.rap.fileupload.FileDetails;
-import org.eclipse.rap.fileupload.FileUploadEvent;
-import org.eclipse.rap.fileupload.FileUploadHandler;
-import org.eclipse.rap.fileupload.FileUploadListener;
-import org.eclipse.rap.fileupload.FileUploadReceiver;
-import org.eclipse.rap.rwt.service.ServerPushSession;
-import org.eclipse.rap.rwt.widgets.FileUpload;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.FormAttachment;
-import org.eclipse.swt.layout.FormData;
-import org.eclipse.swt.layout.FormLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Manage life cycle of a form page that is linked to a given node */
-public class FormPageViewer extends AbstractPageViewer {
-       private final static CmsLog log = CmsLog.getLog(FormPageViewer.class);
-       private static final long serialVersionUID = 5277789504209413500L;
-
-       private final Section mainSection;
-
-       // TODO manage within the CSS
-       private Integer labelColWidth = null;
-       private int rowLayoutHSpacing = 8;
-
-       // Context cached in the viewer
-       // The reference to translate from text to calendar and reverse
-       private DateFormat dateFormat = new SimpleDateFormat(FormUtils.DEFAULT_SHORT_DATE_FORMAT);
-       private CmsImageManager<Control, Node> imageManager;
-       private FileUploadListener fileUploadListener;
-
-       public FormPageViewer(Section mainSection, int style, CmsEditable cmsEditable) throws RepositoryException {
-               super(mainSection, style, cmsEditable);
-               this.mainSection = mainSection;
-
-               if (getCmsEditable().canEdit()) {
-                       fileUploadListener = new FUL();
-               }
-       }
-
-       @Override
-       protected void prepare(SwtEditablePart part, Object caretPosition) {
-               if (part instanceof Img) {
-                       ((Img) part).setFileUploadListener(fileUploadListener);
-               }
-       }
-
-       /** To be overridden.Save the edited part. */
-       protected void save(SwtEditablePart part) throws RepositoryException {
-               Node node = null;
-               if (part instanceof EditableMultiStringProperty) {
-                       EditableMultiStringProperty ept = (EditableMultiStringProperty) part;
-                       // SWT : View
-                       List<String> values = ept.getValues();
-                       // JCR : Model
-                       node = ept.getNode();
-                       String propName = ept.getPropertyName();
-                       if (values.isEmpty()) {
-                               if (node.hasProperty(propName))
-                                       node.getProperty(propName).remove();
-                       } else {
-                               node.setProperty(propName, values.toArray(new String[0]));
-                       }
-                       // => Viewer : Controller
-               } else if (part instanceof EditablePropertyString) {
-                       EditablePropertyString ept = (EditablePropertyString) part;
-                       // SWT : View
-                       String txt = ((Text) ept.getControl()).getText();
-                       // JCR : Model
-                       node = ept.getNode();
-                       String propName = ept.getPropertyName();
-                       if (EclipseUiUtils.isEmpty(txt)) {
-                               if (node.hasProperty(propName))
-                                       node.getProperty(propName).remove();
-                       } else {
-                               setPropertySilently(node, propName, txt);
-                               // node.setProperty(propName, txt);
-                       }
-                       // node.getSession().save();
-                       // => Viewer : Controller
-               } else if (part instanceof EditablePropertyDate) {
-                       EditablePropertyDate ept = (EditablePropertyDate) part;
-                       Calendar cal = FormUtils.parseDate(dateFormat, ((Text) ept.getControl()).getText());
-                       node = ept.getNode();
-                       String propName = ept.getPropertyName();
-                       if (cal == null) {
-                               if (node.hasProperty(propName))
-                                       node.getProperty(propName).remove();
-                       } else {
-                               node.setProperty(propName, cal);
-                       }
-                       // node.getSession().save();
-                       // => Viewer : Controller
-               }
-               // TODO: make this configurable, sometimes we do not want to save the
-               // current session at this stage
-               if (node != null && node.getSession().hasPendingChanges()) {
-                       JcrUtils.updateLastModified(node, true);
-                       node.getSession().save();
-               }
-       }
-
-       @Override
-       protected void updateContent(SwtEditablePart part) throws RepositoryException {
-               if (part instanceof EditableMultiStringProperty) {
-                       EditableMultiStringProperty ept = (EditableMultiStringProperty) part;
-                       // SWT : View
-                       Node node = ept.getNode();
-                       String propName = ept.getPropertyName();
-                       List<String> valStrings = new ArrayList<String>();
-                       if (node.hasProperty(propName)) {
-                               Value[] values = node.getProperty(propName).getValues();
-                               for (Value val : values)
-                                       valStrings.add(val.getString());
-                       }
-                       ept.setValues(valStrings);
-               } else if (part instanceof EditablePropertyString) {
-                       // || part instanceof EditableLink
-                       EditablePropertyString ept = (EditablePropertyString) part;
-                       // JCR : Model
-                       Node node = ept.getNode();
-                       String propName = ept.getPropertyName();
-                       if (node.hasProperty(propName)) {
-                               String value = node.getProperty(propName).getString();
-                               ept.setText(value);
-                       } else
-                               ept.setText("");
-                       // => Viewer : Controller
-               } else if (part instanceof EditablePropertyDate) {
-                       EditablePropertyDate ept = (EditablePropertyDate) part;
-                       // JCR : Model
-                       Node node = ept.getNode();
-                       String propName = ept.getPropertyName();
-                       if (node.hasProperty(propName))
-                               ept.setText(dateFormat.format(node.getProperty(propName).getDate().getTime()));
-                       else
-                               ept.setText("");
-               } else if (part instanceof SectionPart) {
-                       SectionPart sectionPart = (SectionPart) part;
-                       Node partNode = sectionPart.getNode();
-                       // use control AFTER setting style, since it may have been reset
-                       if (part instanceof EditableImage) {
-                               EditableImage editableImage = (EditableImage) part;
-                               imageManager().load(partNode, part.getControl(), editableImage.getPreferredImageSize());
-                       }
-               }
-       }
-
-       // FILE UPLOAD LISTENER
-       protected class FUL implements FileUploadListener {
-
-               public FUL() {
-               }
-
-               public void uploadProgress(FileUploadEvent event) {
-                       // TODO Monitor upload progress
-               }
-
-               public void uploadFailed(FileUploadEvent event) {
-                       throw new IllegalStateException("Upload failed " + event, event.getException());
-               }
-
-               public void uploadFinished(FileUploadEvent event) {
-                       for (FileDetails file : event.getFileDetails()) {
-                               if (log.isDebugEnabled())
-                                       log.debug("Received: " + file.getFileName());
-                       }
-                       mainSection.getDisplay().syncExec(new Runnable() {
-                               @Override
-                               public void run() {
-                                       saveEdit();
-                               }
-                       });
-                       FileUploadHandler uploadHandler = (FileUploadHandler) event.getSource();
-                       uploadHandler.dispose();
-               }
-       }
-
-       // FOCUS OUT LISTENER
-       protected FocusListener createFocusListener() {
-               return new FocusOutListener();
-       }
-
-       private class FocusOutListener implements FocusListener {
-               private static final long serialVersionUID = -6069205786732354186L;
-
-               @Override
-               public void focusLost(FocusEvent event) {
-                       saveEdit();
-               }
-
-               @Override
-               public void focusGained(FocusEvent event) {
-                       // does nothing;
-               }
-       }
-
-       // MOUSE LISTENER
-       @Override
-       protected MouseListener createMouseListener() {
-               return new ML();
-       }
-
-       private class ML extends MouseAdapter {
-               private static final long serialVersionUID = 8526890859876770905L;
-
-               @Override
-               public void mouseDoubleClick(MouseEvent e) {
-                       if (e.button == 1) {
-                               Control source = (Control) e.getSource();
-                               if (getCmsEditable().canEdit()) {
-                                       if (getCmsEditable().isEditing() && !(getEdited() instanceof Img)) {
-                                               if (source == mainSection)
-                                                       return;
-                                               SwtEditablePart part = findDataParent(source);
-                                               upload(part);
-                                       } else {
-                                               getCmsEditable().startEditing();
-                                       }
-                               }
-                       }
-               }
-
-               @Override
-               public void mouseDown(MouseEvent e) {
-                       if (getCmsEditable().isEditing()) {
-                               if (e.button == 1) {
-                                       Control source = (Control) e.getSource();
-                                       SwtEditablePart composite = findDataParent(source);
-                                       Point point = new Point(e.x, e.y);
-                                       if (!(composite instanceof Img))
-                                               edit(composite, source.toDisplay(point));
-                               } else if (e.button == 3) {
-                                       // EditablePart composite = findDataParent((Control) e
-                                       // .getSource());
-                                       // if (styledTools != null)
-                                       // styledTools.show(composite, new Point(e.x, e.y));
-                               }
-                       }
-               }
-
-               protected synchronized void upload(SwtEditablePart part) {
-                       if (part instanceof SectionPart) {
-                               if (part instanceof Img) {
-                                       if (getEdited() == part)
-                                               return;
-                                       edit(part, null);
-                                       layout(part.getControl());
-                               }
-                       }
-               }
-       }
-
-       @Override
-       public Control getControl() {
-               return mainSection;
-       }
-
-       protected CmsImageManager<Control, Node> imageManager() {
-               if (imageManager == null)
-                       imageManager = (CmsImageManager<Control, Node>) CmsSwtUtils.getCmsView(mainSection).getImageManager();
-               return imageManager;
-       }
-
-       // LOCAL UI HELPERS
-       protected Section createSectionIfNeeded(Composite body, Node node) throws RepositoryException {
-               Section section = null;
-               if (node != null) {
-                       section = new Section(body, SWT.NO_FOCUS, node);
-                       section.setLayoutData(CmsSwtUtils.fillWidth());
-                       section.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               }
-               return section;
-       }
-
-       protected void createSimpleLT(Composite bodyRow, Node node, String propName, String label, String msg)
-                       throws RepositoryException {
-               if (getCmsEditable().canEdit() || node.hasProperty(propName)) {
-                       createPropertyLbl(bodyRow, label);
-                       EditablePropertyString eps = new EditablePropertyString(bodyRow, SWT.WRAP | SWT.LEFT, node, propName, msg);
-                       eps.setMouseListener(getMouseListener());
-                       eps.setFocusListener(getFocusListener());
-                       eps.setLayoutData(CmsSwtUtils.fillWidth());
-               }
-       }
-
-       protected void createMultiStringLT(Composite bodyRow, Node node, String propName, String label, String msg)
-                       throws RepositoryException {
-               boolean canEdit = getCmsEditable().canEdit();
-               if (canEdit || node.hasProperty(propName)) {
-                       createPropertyLbl(bodyRow, label);
-
-                       List<String> valueStrings = new ArrayList<String>();
-
-                       if (node.hasProperty(propName)) {
-                               Value[] values = node.getProperty(propName).getValues();
-                               for (Value value : values)
-                                       valueStrings.add(value.getString());
-                       }
-
-                       // TODO use a drop down to display possible values to the end user
-                       EditableMultiStringProperty emsp = new EditableMultiStringProperty(bodyRow, SWT.SINGLE | SWT.LEAD, node,
-                                       propName, valueStrings, new String[] { "Implement this" }, msg,
-                                       canEdit ? getRemoveValueSelListener() : null);
-                       addListeners(emsp);
-                       // emsp.setMouseListener(getMouseListener());
-                       emsp.setStyle(FormStyle.propertyMessage.style());
-                       emsp.setLayoutData(CmsSwtUtils.fillWidth());
-               }
-       }
-
-       protected Label createPropertyLbl(Composite parent, String value) {
-               return createPropertyLbl(parent, value, SWT.NONE);
-       }
-
-       protected Label createPropertyLbl(Composite parent, String value, int vAlign) {
-               // boolean isSmall = CmsView.getCmsView(parent).getUxContext().isSmall();
-               Label label = new Label(parent, SWT.LEAD | SWT.WRAP);
-               label.setText(value + " ");
-               CmsSwtUtils.style(label, FormStyle.propertyLabel.style());
-               GridData gd = new GridData(SWT.LEAD, vAlign, false, false);
-               if (labelColWidth != null)
-                       gd.widthHint = labelColWidth;
-               label.setLayoutData(gd);
-               return label;
-       }
-
-       protected Label newStyledLabel(Composite parent, String style, String value) {
-               Label label = new Label(parent, SWT.NONE);
-               label.setText(value);
-               CmsSwtUtils.style(label, style);
-               return label;
-       }
-
-       protected Composite createRowLayoutComposite(Composite parent) throws RepositoryException {
-               Composite bodyRow = new Composite(parent, SWT.NO_FOCUS);
-               bodyRow.setLayoutData(CmsSwtUtils.fillWidth());
-               RowLayout rl = new RowLayout(SWT.WRAP);
-               rl.type = SWT.HORIZONTAL;
-               rl.spacing = rowLayoutHSpacing;
-               rl.marginHeight = rl.marginWidth = 0;
-               rl.marginTop = rl.marginBottom = rl.marginLeft = rl.marginRight = 0;
-               bodyRow.setLayout(rl);
-               return bodyRow;
-       }
-
-       protected Composite createAddImgComposite(final Section section, Composite parent, final Node parentNode)
-                       throws RepositoryException {
-
-               Composite body = new Composite(parent, SWT.NO_FOCUS);
-               body.setLayout(new GridLayout());
-
-               FormFileUploadReceiver receiver = new FormFileUploadReceiver(section, parentNode, null);
-               final FileUploadHandler currentUploadHandler = new FileUploadHandler(receiver);
-               if (fileUploadListener != null)
-                       currentUploadHandler.addUploadListener(fileUploadListener);
-
-               // Button creation
-               final FileUpload fileUpload = new FileUpload(body, SWT.BORDER);
-               fileUpload.setText("Import an image");
-               fileUpload.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
-               fileUpload.addSelectionListener(new SelectionAdapter() {
-                       private static final long serialVersionUID = 4869523412991968759L;
-
-                       @Override
-                       public void widgetSelected(SelectionEvent e) {
-                               ServerPushSession pushSession = new ServerPushSession();
-                               pushSession.start();
-                               String uploadURL = currentUploadHandler.getUploadUrl();
-                               fileUpload.submit(uploadURL);
-                       }
-               });
-
-               return body;
-       }
-
-       protected class FormFileUploadReceiver extends FileUploadReceiver {
-
-               private Node context;
-               private Section section;
-               private String name;
-
-               public FormFileUploadReceiver(Section section, Node context, String name) {
-                       this.context = context;
-                       this.section = section;
-                       this.name = name;
-               }
-
-               @Override
-               public void receive(InputStream stream, FileDetails details) throws IOException {
-
-                       if (name == null)
-                               name = details.getFileName();
-
-                       // TODO clean image name more carefully
-                       String cleanedName = name.replaceAll("[^a-zA-Z0-9-.]", "");
-                       // We add a unique prefix to workaround the cache issue: when
-                       // deleting and re-adding a new image with same name, the end user
-                       // browser will use the cache and the image will remain unchanged
-                       // for a while
-                       cleanedName = System.currentTimeMillis() % 100000 + "_" + cleanedName;
-
-                       imageManager().uploadImage(context, context, cleanedName, stream, details.getContentType());
-                       // TODO clean refresh strategy
-                       section.getDisplay().asyncExec(new Runnable() {
-                               @Override
-                               public void run() {
-                                       try {
-                                               FormPageViewer.this.refresh(section);
-                                               section.layout();
-                                               section.getParent().layout();
-                                       } catch (RepositoryException re) {
-                                               throw new JcrException("Unable to refresh " + "image section for " + context, re);
-                                       }
-                               }
-                       });
-               }
-       }
-
-       protected void addListeners(StyledControl control) {
-               control.setMouseListener(getMouseListener());
-               control.setFocusListener(getFocusListener());
-       }
-
-       protected Img createImgComposite(Composite parent, Node node, Point preferredSize) throws RepositoryException {
-               Img img = new Img(parent, SWT.NONE, node, new Cms2DSize(preferredSize.x, preferredSize.y)) {
-                       private static final long serialVersionUID = 1297900641952417540L;
-
-                       @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));
-                       }
-               };
-               img.setLayoutData(CmsSwtUtils.grabWidth(SWT.CENTER, SWT.DEFAULT));
-               updateContent(img);
-               addListeners(img);
-               return img;
-       }
-
-       protected Composite addDeleteAbility(final Section section, final Node sessionNode, int topWeight,
-                       int rightWeight) {
-               Composite comp = new Composite(section, SWT.NONE);
-               comp.setLayoutData(CmsSwtUtils.fillAll());
-               comp.setLayout(new FormLayout());
-
-               // The body to be populated
-               Composite body = new Composite(comp, SWT.NO_FOCUS);
-               body.setLayoutData(EclipseUiUtils.fillFormData());
-
-               if (getCmsEditable().canEdit()) {
-                       // the delete button
-                       Button deleteBtn = new Button(comp, SWT.FLAT);
-                       CmsSwtUtils.style(deleteBtn, FormStyle.deleteOverlay.style());
-                       FormData formData = new FormData();
-                       formData.right = new FormAttachment(rightWeight, 0);
-                       formData.top = new FormAttachment(topWeight, 0);
-                       deleteBtn.setLayoutData(formData);
-                       deleteBtn.moveAbove(body);
-
-                       deleteBtn.addSelectionListener(new SelectionAdapter() {
-                               private static final long serialVersionUID = 4304223543657238462L;
-
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       super.widgetSelected(e);
-                                       if (MessageDialog.openConfirm(section.getShell(), "Confirm deletion",
-                                                       "Are you really you want to remove this?")) {
-                                               Session session;
-                                               try {
-                                                       session = sessionNode.getSession();
-                                                       Section parSection = section.getParentSection();
-                                                       sessionNode.remove();
-                                                       session.save();
-                                                       refresh(parSection);
-                                                       layout(parSection);
-                                               } catch (RepositoryException re) {
-                                                       throw new JcrException("Unable to delete " + sessionNode, re);
-                                               }
-
-                                       }
-
-                               }
-                       });
-               }
-               return body;
-       }
-
-//     // LOCAL HELPERS FOR NODE MANAGEMENT
-//     private Node getOrCreateNode(Node parent, String nodeName, String nodeType) throws RepositoryException {
-//             Node node = null;
-//             if (getCmsEditable().canEdit() && !parent.hasNode(nodeName)) {
-//                     node = JcrUtils.mkdirs(parent, nodeName, nodeType);
-//                     parent.getSession().save();
-//             }
-//
-//             if (getCmsEditable().canEdit() || parent.hasNode(nodeName))
-//                     node = parent.getNode(nodeName);
-//
-//             return node;
-//     }
-
-       private SelectionListener getRemoveValueSelListener() {
-               return new SelectionAdapter() {
-                       private static final long serialVersionUID = 9022259089907445195L;
-
-                       @Override
-                       public void widgetSelected(SelectionEvent e) {
-                               Object source = e.getSource();
-                               if (source instanceof Button) {
-                                       Button btn = (Button) source;
-                                       Object obj = btn.getData(FormConstants.LINKED_VALUE);
-                                       SwtEditablePart ep = findDataParent(btn);
-                                       if (ep != null && ep instanceof EditableMultiStringProperty) {
-                                               EditableMultiStringProperty emsp = (EditableMultiStringProperty) ep;
-                                               List<String> values = emsp.getValues();
-                                               if (values.contains(obj)) {
-                                                       values.remove(values.indexOf(obj));
-                                                       emsp.setValues(values);
-                                                       try {
-                                                               save(emsp);
-                                                               // TODO workaround to force refresh
-                                                               edit(emsp, 0);
-                                                               cancelEdit();
-                                                       } catch (RepositoryException e1) {
-                                                               throw new JcrException("Unable to remove value " + obj, e1);
-                                                       }
-                                                       layout(emsp);
-                                               }
-                                       }
-                               }
-                       }
-               };
-       }
-
-       protected void setPropertySilently(Node node, String propName, String value) throws RepositoryException {
-               try {
-                       // TODO Clean this:
-                       // Format strings to replace \n
-                       value = value.replaceAll("\n", "<br/>");
-                       // Do not make the update if validation fails
-                       try {
-                               MarkupValidatorCopy.getInstance().validate(value);
-                       } catch (Exception e) {
-                               log.warn("Cannot set [" + value + "] on prop " + propName + "of " + node
-                                               + ", String cannot be validated - " + e.getMessage());
-                               return;
-                       }
-                       // TODO check if the newly created property is of the correct type,
-                       // otherwise the property will be silently created with a STRING
-                       // property type.
-                       node.setProperty(propName, value);
-               } catch (ValueFormatException vfe) {
-                       log.warn("Cannot set [" + value + "] on prop " + propName + "of " + node + " - " + vfe.getMessage());
-               }
-       }
-}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormStyle.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormStyle.java
deleted file mode 100644 (file)
index 709ecd0..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.argeo.cms.ui.forms;
-
-import org.argeo.api.cms.ux.CmsStyle;
-
-/** Syles used */
-public enum FormStyle implements CmsStyle {
-       // Main
-       form, title,
-       // main part
-       header, headerBtn, headerCombo, section, sectionHeader,
-       // Property fields
-       propertyLabel, propertyText, propertyMessage, errorMessage,
-       // Date
-       popupCalendar,
-       // Buttons
-       starred, unstarred, starOverlay, editOverlay, deleteOverlay, updateOverlay, deleteOverlaySmall, calendar, delete,
-       // Contacts
-       email, address, phone, website,
-       // Social Media
-       facebook, twitter, linkedIn, instagram;
-
-       @Override
-       public String getClassPrefix() {
-               return "argeo-form";
-       }
-
-       // TODO clean button style management
-       public final static String BUTTON_SUFFIX = "_btn";
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormUtils.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormUtils.java
deleted file mode 100644 (file)
index ef49c8a..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-package org.argeo.cms.ui.forms;
-
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsView;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.eclipse.jface.fieldassist.ControlDecoration;
-import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Utilitary methods to ease implementation of CMS forms */
-public class FormUtils {
-       private final static CmsLog log = CmsLog.getLog(FormUtils.class);
-
-       public final static String DEFAULT_SHORT_DATE_FORMAT = "dd/MM/yyyy";
-
-       /** Best effort to convert a String to a calendar. Fails silently */
-       public static Calendar parseDate(DateFormat dateFormat, String calStr) {
-               Calendar cal = null;
-               if (EclipseUiUtils.notEmpty(calStr)) {
-                       try {
-                               Date date = dateFormat.parse(calStr);
-                               cal = new GregorianCalendar();
-                               cal.setTime(date);
-                       } catch (ParseException pe) {
-                               // Silent
-                               log.warn("Unable to parse date: " + calStr + " - msg: "
-                                               + pe.getMessage());
-                       }
-               }
-               return cal;
-       }
-
-       /** Add a double click listener on tables that display a JCR node list */
-       public static void addCanonicalDoubleClickListener(final TableViewer v) {
-               v.addDoubleClickListener(new IDoubleClickListener() {
-
-                       @Override
-                       public void doubleClick(DoubleClickEvent event) {
-                               CmsView cmsView = CmsUiUtils.getCmsView();
-                               Node node = (Node) ((IStructuredSelection) event.getSelection())
-                                               .getFirstElement();
-                               try {
-                                       cmsView.navigateTo(node.getPath());
-                               } catch (RepositoryException e) {
-                                       throw new CmsException("Unable to get path for node "
-                                                       + node + " before calling navigateTo(path)", e);
-                               }
-                       }
-               });
-       }
-
-       // MANAGE ERROR DECORATION
-
-       public static ControlDecoration addDecoration(final Text text) {
-               final ControlDecoration dynDecoration = new ControlDecoration(text,
-                               SWT.LEFT);
-               Image icon = getDecorationImage(FieldDecorationRegistry.DEC_ERROR);
-               dynDecoration.setImage(icon);
-               dynDecoration.setMarginWidth(3);
-               dynDecoration.hide();
-               return dynDecoration;
-       }
-
-       public static void refreshDecoration(Text text, ControlDecoration deco,
-                       boolean isValid, boolean clean) {
-               if (isValid || clean) {
-                       text.setBackground(null);
-                       deco.hide();
-               } else {
-                       text.setBackground(new Color(text.getDisplay(), 250, 200, 150));
-                       deco.show();
-               }
-       }
-
-       public static Image getDecorationImage(String image) {
-               FieldDecorationRegistry registry = FieldDecorationRegistry.getDefault();
-               return registry.getFieldDecoration(image).getImage();
-       }
-
-       public static void addCompulsoryDecoration(Label label) {
-               final ControlDecoration dynDecoration = new ControlDecoration(label,
-                               SWT.RIGHT | SWT.TOP);
-               Image icon = getDecorationImage(FieldDecorationRegistry.DEC_REQUIRED);
-               dynDecoration.setImage(icon);
-               dynDecoration.setMarginWidth(3);
-       }
-
-       // TODO the read only generation of read only links for various contact type
-       // should be factorised in the cms Utils.
-       /**
-        * Creates the read-only HTML snippet to display in a label with styling
-        * enabled in order to provide a click-able phone number
-        */
-       public static String getPhoneLink(String value) {
-               return getPhoneLink(value, value);
-       }
-
-       /**
-        * Creates the read-only HTML snippet to display in a label with styling
-        * enabled in order to provide a click-able phone number
-        * 
-        * @param value
-        * @param label
-        *            a potentially distinct label
-        * @return
-        */
-       public static String getPhoneLink(String value, String label) {
-               StringBuilder builder = new StringBuilder();
-               builder.append("<a href=\"tel:");
-               builder.append(value).append("\" target=\"_blank\" >").append(label)
-                               .append("</a>");
-               return builder.toString();
-       }
-
-       /**
-        * Creates the read-only HTML snippet to display in a label with styling
-        * enabled in order to provide a click-able mail
-        */
-       public static String getMailLink(String value) {
-               return getMailLink(value, value);
-       }
-
-       /**
-        * Creates the read-only HTML snippet to display in a label with styling
-        * enabled in order to provide a click-able mail
-        * 
-        * @param value
-        * @param label
-        *            a potentially distinct label
-        * @return
-        */
-       public static String getMailLink(String value, String label) {
-               StringBuilder builder = new StringBuilder();
-               value = replaceAmpersand(value);
-               builder.append("<a href=\"mailto:");
-               builder.append(value).append("\" >").append(label).append("</a>");
-               return builder.toString();
-       }
-
-       /**
-        * Creates the read-only HTML snippet to display in a label with styling
-        * enabled in order to provide a click-able link
-        */
-       public static String getUrlLink(String value) {
-               return getUrlLink(value, value);
-       }
-
-       /**
-        * Creates the read-only HTML snippet to display in a label with styling
-        * enabled in order to provide a click-able link
-        */
-       public static String getUrlLink(String value, String label) {
-               StringBuilder builder = new StringBuilder();
-               value = replaceAmpersand(value);
-               label = replaceAmpersand(label);
-               if (!(value.startsWith("http://") || value.startsWith("https://")))
-                       value = "http://" + value;
-               builder.append("<a href=\"");
-               builder.append(value + "\" target=\"_blank\" >" + label + "</a>");
-               return builder.toString();
-       }
-
-       private static String AMPERSAND = "&#38;";
-
-       /**
-        * Cleans a String by replacing any '&#38;' by its HTML encoding '&#38;#38;' to
-        * avoid <code>SAXParseException</code> while rendering HTML with RWT
-        */
-       public static String replaceAmpersand(String value) {
-               value = value.replaceAll("&(?![#a-zA-Z0-9]+;)", AMPERSAND);
-               return value;
-       }
-
-       // Prevents instantiation
-       private FormUtils() {
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/MarkupValidatorCopy.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/MarkupValidatorCopy.java
deleted file mode 100644 (file)
index 3f588d1..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-package org.argeo.cms.ui.forms;
-
-import java.io.StringReader;
-import java.text.MessageFormat;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.eclipse.rap.rwt.SingletonUtil;
-import org.eclipse.swt.widgets.Widget;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.helpers.DefaultHandler;
-
-/**
- * Copy of RAP v2.3 since it is in an internal package.
- */
-class MarkupValidatorCopy {
-
-       // Used by Eclipse Scout project
-       public static final String MARKUP_VALIDATION_DISABLED = "org.eclipse.rap.rwt.markupValidationDisabled";
-
-       private static final String DTD = createDTD();
-       private static final Map<String, String[]> SUPPORTED_ELEMENTS = createSupportedElementsMap();
-       private final SAXParser saxParser;
-
-       public static MarkupValidatorCopy getInstance() {
-               return SingletonUtil.getSessionInstance(MarkupValidatorCopy.class);
-       }
-
-       public MarkupValidatorCopy() {
-               saxParser = createSAXParser();
-       }
-
-       public void validate(String text) {
-               StringBuilder markup = new StringBuilder();
-               markup.append(DTD);
-               markup.append("<html>");
-               markup.append(text);
-               markup.append("</html>");
-               InputSource inputSource = new InputSource(new StringReader(markup.toString()));
-               try {
-                       saxParser.parse(inputSource, new MarkupHandler());
-               } catch (RuntimeException exception) {
-                       throw exception;
-               } catch (Exception exception) {
-                       throw new IllegalArgumentException("Failed to parse markup text", exception);
-               }
-       }
-
-       public static boolean isValidationDisabledFor(Widget widget) {
-               return Boolean.TRUE.equals(widget.getData(MARKUP_VALIDATION_DISABLED));
-       }
-
-       private static SAXParser createSAXParser() {
-               SAXParser result = null;
-               SAXParserFactory parserFactory = SAXParserFactory.newInstance();
-               try {
-                       result = parserFactory.newSAXParser();
-               } catch (Exception exception) {
-                       throw new RuntimeException("Failed to create SAX parser", exception);
-               }
-               return result;
-       }
-
-       private static String createDTD() {
-               StringBuilder result = new StringBuilder();
-               result.append("<!DOCTYPE html [");
-               result.append("<!ENTITY quot \"&#34;\">");
-               result.append("<!ENTITY amp \"&#38;\">");
-               result.append("<!ENTITY apos \"&#39;\">");
-               result.append("<!ENTITY lt \"&#60;\">");
-               result.append("<!ENTITY gt \"&#62;\">");
-               result.append("<!ENTITY nbsp \"&#160;\">");
-               result.append("<!ENTITY ensp \"&#8194;\">");
-               result.append("<!ENTITY emsp \"&#8195;\">");
-               result.append("<!ENTITY ndash \"&#8211;\">");
-               result.append("<!ENTITY mdash \"&#8212;\">");
-               result.append("]>");
-               return result.toString();
-       }
-
-       private static Map<String, String[]> createSupportedElementsMap() {
-               Map<String, String[]> result = new HashMap<String, String[]>();
-               result.put("html", new String[0]);
-               result.put("br", new String[0]);
-               result.put("b", new String[] { "style" });
-               result.put("strong", new String[] { "style" });
-               result.put("i", new String[] { "style" });
-               result.put("em", new String[] { "style" });
-               result.put("sub", new String[] { "style" });
-               result.put("sup", new String[] { "style" });
-               result.put("big", new String[] { "style" });
-               result.put("small", new String[] { "style" });
-               result.put("del", new String[] { "style" });
-               result.put("ins", new String[] { "style" });
-               result.put("code", new String[] { "style" });
-               result.put("samp", new String[] { "style" });
-               result.put("kbd", new String[] { "style" });
-               result.put("var", new String[] { "style" });
-               result.put("cite", new String[] { "style" });
-               result.put("dfn", new String[] { "style" });
-               result.put("q", new String[] { "style" });
-               result.put("abbr", new String[] { "style", "title" });
-               result.put("span", new String[] { "style" });
-               result.put("img", new String[] { "style", "src", "width", "height", "title", "alt" });
-               result.put("a", new String[] { "style", "href", "target", "title" });
-               return result;
-       }
-
-       private static class MarkupHandler extends DefaultHandler {
-
-               @Override
-               public void startElement(String uri, String localName, String name, Attributes attributes) {
-                       checkSupportedElements(name, attributes);
-                       checkSupportedAttributes(name, attributes);
-                       checkMandatoryAttributes(name, attributes);
-               }
-
-               private static void checkSupportedElements(String elementName, Attributes attributes) {
-                       if (!SUPPORTED_ELEMENTS.containsKey(elementName)) {
-                               throw new IllegalArgumentException("Unsupported element in markup text: " + elementName);
-                       }
-               }
-
-               private static void checkSupportedAttributes(String elementName, Attributes attributes) {
-                       if (attributes.getLength() > 0) {
-                               List<String> supportedAttributes = Arrays.asList(SUPPORTED_ELEMENTS.get(elementName));
-                               int index = 0;
-                               String attributeName = attributes.getQName(index);
-                               while (attributeName != null) {
-                                       if (!supportedAttributes.contains(attributeName)) {
-                                               String message = "Unsupported attribute \"{0}\" for element \"{1}\" in markup text";
-                                               message = MessageFormat.format(message, new Object[] { attributeName, elementName });
-                                               throw new IllegalArgumentException(message);
-                                       }
-                                       index++;
-                                       attributeName = attributes.getQName(index);
-                               }
-                       }
-               }
-
-               private static void checkMandatoryAttributes(String elementName, Attributes attributes) {
-                       checkIntAttribute(elementName, attributes, "img", "width");
-                       checkIntAttribute(elementName, attributes, "img", "height");
-               }
-
-               private static void checkIntAttribute(String elementName, Attributes attributes, String checkedElementName,
-                               String checkedAttributeName) {
-                       if (checkedElementName.equals(elementName)) {
-                               String attribute = attributes.getValue(checkedAttributeName);
-                               try {
-                                       Integer.parseInt(attribute);
-                               } catch (NumberFormatException exception) {
-                                       String message = "Mandatory attribute \"{0}\" for element \"{1}\" is missing or not a valid integer";
-                                       Object[] arguments = new Object[] { checkedAttributeName, checkedElementName };
-                                       message = MessageFormat.format(message, arguments);
-                                       throw new IllegalArgumentException(message);
-                               }
-                       }
-               }
-
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/package-info.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/package-info.java
deleted file mode 100644 (file)
index 5f954c1..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Argeo CMS forms, based on SWT/JFace. */
-package org.argeo.cms.ui.forms;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/CmsFsBrowser.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/CmsFsBrowser.java
deleted file mode 100644 (file)
index d9c1c12..0000000
+++ /dev/null
@@ -1,524 +0,0 @@
-package org.argeo.cms.ui.fs;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileSystem;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.spi.FileSystemProvider;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.Session;
-
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.eclipse.ui.ColumnDefinition;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.fs.FileIconNameLabelProvider;
-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.jcr.JcrUtils;
-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 CMS browser composite: a sashForm layout with bookmarks at the left
- * hand side, a simple table in the middle and an overview at right hand side.
- */
-public class CmsFsBrowser extends Composite {
-       // private final static Log log = LogFactory.getLog(CmsFsBrowser.class);
-       private static final long serialVersionUID = -40347919096946585L;
-
-       private final FileSystemProvider nodeFileSystemProvider;
-       private final Node currentBaseContext;
-
-       // UI Parts for the browser
-       private Composite leftPannelCmp;
-       private Composite filterCmp;
-       private Text filterTxt;
-       private FsTableViewer directoryDisplayViewer;
-       private Composite rightPannelCmp;
-
-       private FsContextMenu contextMenu;
-
-       // Local context (this composite is state full)
-       private Path initialPath;
-       private Path currDisplayedFolder;
-       private Path currSelected;
-
-       // local variables (to be cleaned)
-       private int bookmarkColWith = 500;
-
-       /*
-        * WARNING: unfinalised implementation of the mechanism to retrieve base
-        * paths
-        */
-
-       private final static String NODE_PREFIX = "node://";
-
-       private String getCurrentHomePath() {
-               Session session = null;
-               try {
-                       Repository repo = currentBaseContext.getSession().getRepository();
-                       session = CurrentUser.tryAs(() -> repo.login());
-                       String homepath = CmsJcrUtils.getUserHome(session).getPath();
-                       return homepath;
-               } catch (Exception e) {
-                       throw new CmsException("Cannot retrieve Current User Home Path", e);
-               } finally {
-                       JcrUtils.logoutQuietly(session);
-               }
-       }
-
-       protected Path[] getMyFilesPath() {
-               // return Paths.get(System.getProperty("user.dir"));
-               String currHomeUriStr = NODE_PREFIX + getCurrentHomePath();
-               try {
-                       URI uri = new URI(currHomeUriStr);
-                       FileSystem fileSystem = nodeFileSystemProvider.getFileSystem(uri);
-                       if (fileSystem == null) {
-                               PrivilegedExceptionAction<FileSystem> pea = new PrivilegedExceptionAction<FileSystem>() {
-                                       @Override
-                                       public FileSystem run() throws Exception {
-                                               return nodeFileSystemProvider.newFileSystem(uri, null);
-                                       }
-
-                               };
-                               fileSystem = CurrentUser.tryAs(pea);
-                       }
-                       Path[] paths = { fileSystem.getPath(getCurrentHomePath()), fileSystem.getPath("/") };
-                       return paths;
-               } catch (URISyntaxException | PrivilegedActionException e) {
-                       throw new RuntimeException("unable to initialise home file system for " + currHomeUriStr, e);
-               }
-       }
-
-       private Path[] getMyGroupsFilesPath() {
-               // TODO
-               Path[] paths = { Paths.get(System.getProperty("user.dir")), Paths.get("/tmp") };
-               return paths;
-       }
-
-       private Path[] getMyBookmarks() {
-               // TODO
-               Path[] paths = { Paths.get(System.getProperty("user.dir")), Paths.get("/tmp"), Paths.get("/opt") };
-               return paths;
-       }
-
-       /* End of warning */
-
-       public CmsFsBrowser(Composite parent, int style, Node context, FileSystemProvider fileSystemProvider) {
-               super(parent, style);
-               this.nodeFileSystemProvider = fileSystemProvider;
-               this.currentBaseContext = context;
-
-               this.setLayout(EclipseUiUtils.noSpaceGridLayout());
-
-               SashForm form = new SashForm(this, SWT.HORIZONTAL);
-
-               leftPannelCmp = new Composite(form, SWT.NO_FOCUS);
-               // Bookmarks are still static
-               populateBookmarks(leftPannelCmp);
-
-               Composite centerCmp = new Composite(form, SWT.BORDER | SWT.NO_FOCUS);
-               createDisplay(centerCmp);
-
-               rightPannelCmp = new Composite(form, SWT.NO_FOCUS);
-
-               form.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               form.setWeights(new int[] { 15, 40, 20 });
-       }
-
-       void refresh() {
-               modifyFilter(false);
-               // also refresh bookmarks and groups
-       }
-
-       private void createDisplay(final Composite parent) {
-               parent.setLayout(EclipseUiUtils.noSpaceGridLayout());
-
-               // top filter
-               filterCmp = new Composite(parent, SWT.NO_FOCUS);
-               filterCmp.setLayoutData(EclipseUiUtils.fillWidth());
-               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());
-
-               // table.addKeyListener(new KeyListener() {
-               // private static final long serialVersionUID = -8083424284436715709L;
-               //
-               // @Override
-               // public void keyReleased(KeyEvent e) {
-               // }
-               //
-               // @Override
-               // public void keyPressed(KeyEvent e) {
-               // if (log.isDebugEnabled())
-               // log.debug("Key event received: " + e.keyCode);
-               // IStructuredSelection selection = (IStructuredSelection)
-               // directoryDisplayViewer.getSelection();
-               // Path selected = null;
-               // if (!selection.isEmpty())
-               // selected = ((Path) selection.getFirstElement());
-               // if (e.keyCode == SWT.CR) {
-               // if (!Files.isDirectory(selected))
-               // return;
-               // if (selected != null) {
-               // currDisplayedFolder = selected;
-               // directoryDisplayViewer.setInput(currDisplayedFolder, "*");
-               // }
-               // } else if (e.keyCode == SWT.BS) {
-               // currDisplayedFolder = currDisplayedFolder.getParent();
-               // directoryDisplayViewer.setInput(currDisplayedFolder, "*");
-               // directoryDisplayViewer.getTable().setFocus();
-               // }
-               // }
-               // });
-
-               directoryDisplayViewer.addSelectionChangedListener(new ISelectionChangedListener() {
-
-                       @Override
-                       public void selectionChanged(SelectionChangedEvent event) {
-                               IStructuredSelection selection = (IStructuredSelection) directoryDisplayViewer.getSelection();
-                               Path selected = null;
-                               if (selection.isEmpty())
-                                       setSelected(null);
-                               else
-                                       selected = ((Path) selection.getFirstElement());
-                               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())
-                                       selected = ((Path) selection.getFirstElement());
-                               if (selected != null) {
-                                       if (!Files.isDirectory(selected))
-                                               return;
-                                       setInput(selected);
-                               }
-                       }
-               });
-
-               // The context menu
-               contextMenu = new FsContextMenu(this);
-
-               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), currDisplayedFolder);
-                               }
-                       }
-               });
-       }
-
-       private void addPathElementBtn(Path path) {
-               Button elemBtn = new Button(filterCmp, SWT.PUSH);
-               String nameStr;
-               if (path.toString().equals("/"))
-                       nameStr = "[jcr:root]";
-               else
-                       nameStr = path.getFileName().toString();
-               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(currDisplayedFolder))
-                       return;
-               currDisplayedFolder = path;
-
-               Path diff = initialPath.relativize(currDisplayedFolder);
-
-               for (Control child : filterCmp.getChildren())
-                       if (!child.equals(filterTxt))
-                               child.dispose();
-
-               addPathElementBtn(initialPath);
-               Path currTarget = initialPath;
-               if (!diff.toString().equals(""))
-                       for (Path pathElem : diff) {
-                               currTarget = currTarget.resolve(pathElem);
-                               addPathElementBtn(currTarget);
-                       }
-
-               filterTxt.setText("");
-               filterTxt.moveBelow(null);
-               setSelected(null);
-               filterCmp.getParent().layout(true, true);
-       }
-
-       private void setSelected(Path path) {
-               currSelected = path;
-               setOverviewInput(path);
-       }
-
-       public Viewer getViewer() {
-               return directoryDisplayViewer;
-       }
-
-       private void populateBookmarks(Composite parent) {
-               CmsSwtUtils.clear(parent);
-               parent.setLayout(new GridLayout());
-               ISelectionChangedListener selList = new BookmarksSelChangeListener();
-
-               FsTableViewer homeViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
-               Table table = homeViewer.configureDefaultSingleColumnTable(bookmarkColWith);
-               GridData gd = EclipseUiUtils.fillWidth();
-               gd.horizontalIndent = 10;
-               table.setLayoutData(gd);
-               homeViewer.addSelectionChangedListener(selList);
-               homeViewer.setPathsInput(getMyFilesPath());
-
-               appendTitle(parent, "Shared files");
-               FsTableViewer groupsViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
-               table = groupsViewer.configureDefaultSingleColumnTable(bookmarkColWith);
-               gd = EclipseUiUtils.fillWidth();
-               gd.horizontalIndent = 10;
-               table.setLayoutData(gd);
-               groupsViewer.addSelectionChangedListener(selList);
-               groupsViewer.setPathsInput(getMyGroupsFilesPath());
-
-               appendTitle(parent, "My bookmarks");
-               FsTableViewer bookmarksViewer = new FsTableViewer(parent, SWT.SINGLE | SWT.NO_SCROLL);
-               table = bookmarksViewer.configureDefaultSingleColumnTable(bookmarkColWith);
-               gd = EclipseUiUtils.fillWidth();
-               gd.horizontalIndent = 10;
-               table.setLayoutData(gd);
-               bookmarksViewer.addSelectionChangedListener(selList);
-               bookmarksViewer.setPathsInput(getMyBookmarks());
-       }
-
-       /**
-        * 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 CmsException("Cannot display details for " + path.toString(), e);
-               }
-       }
-
-       private void addFilterPanel(Composite parent) {
-               RowLayout rl = new RowLayout(SWT.HORIZONTAL);
-               rl.wrap = true;
-               parent.setLayout(rl);
-               // 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 CmsException(
-                                       "Unable to determine unique child existence and get it under " + parent + " with filter " + filter,
-                                       ioe);
-               }
-       }
-
-       private void modifyFilter(boolean fromOutside) {
-               if (!fromOutside)
-                       if (currDisplayedFolder != null) {
-                               String filter = filterTxt.getText() + "*";
-                               directoryDisplayViewer.setInput(currDisplayedFolder, filter);
-                       }
-       }
-
-       private class BookmarksSelChangeListener implements ISelectionChangedListener {
-
-               @Override
-               public void selectionChanged(SelectionChangedEvent event) {
-                       IStructuredSelection selection = (IStructuredSelection) event.getSelection();
-                       if (selection.isEmpty())
-                               return;
-                       else {
-                               Path newSelected = (Path) selection.getFirstElement();
-                               if (newSelected.equals(currDisplayedFolder) && newSelected.equals(initialPath))
-                                       return;
-                               initialPath = newSelected;
-                               setInput(newSelected);
-                       }
-               }
-       }
-
-       // Simplify UI implementation
-       private void addProperty(Composite parent, String propName, String value) {
-               Label contextL = new Label(parent, SWT.NONE);
-               contextL.setText(propName + ": " + value);
-       }
-
-       private Label appendTitle(Composite parent, String value) {
-               Label titleLbl = new Label(parent, SWT.NONE);
-               titleLbl.setText(value);
-               titleLbl.setFont(EclipseUiUtils.getBoldFont(parent));
-               GridData gd = EclipseUiUtils.fillWidth();
-               gd.horizontalIndent = 5;
-               gd.verticalIndent = 5;
-               titleLbl.setLayoutData(gd);
-               return titleLbl;
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FileDrop.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FileDrop.java
deleted file mode 100644 (file)
index e875b5a..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.argeo.cms.ui.fs;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.eclipse.ui.specific.FileDropAdapter;
-import org.eclipse.swt.dnd.DND;
-import org.eclipse.swt.dnd.DropTarget;
-import org.eclipse.swt.dnd.DropTargetEvent;
-import org.eclipse.swt.widgets.Control;
-
-/** Allows a control to receive file drops. */
-public class FileDrop {
-       private final static CmsLog log = CmsLog.getLog(FileDrop.class);
-
-       public void createDropTarget(Control control) {
-               FileDropAdapter fileDropAdapter = new FileDropAdapter() {
-                       @Override
-                       protected void processUpload(InputStream in, String fileName, String contentType) throws IOException {
-                               if (log.isDebugEnabled())
-                                       log.debug("Process upload of " + fileName + " (" + contentType + ")");
-                               processFileUpload(in, fileName, contentType);
-                       }
-               };
-               DropTarget dropTarget = new DropTarget(control, DND.DROP_MOVE | DND.DROP_COPY);
-               fileDropAdapter.prepareDropTarget(control, dropTarget);
-       }
-
-       public void handleFileDrop(Control control, DropTargetEvent event) {
-       }
-
-       /** Executed in UI thread */
-       protected void processFileUpload(InputStream in, String fileName, String contentType) throws IOException {
-
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FsContextMenu.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FsContextMenu.java
deleted file mode 100644 (file)
index 1fb3c2a..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-package org.argeo.cms.ui.fs;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Method;
-import java.net.URI;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.eclipse.ui.dialogs.SingleValue;
-import org.eclipse.jface.dialogs.MessageDialog;
-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.FileDialog;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-
-/** Generic popup context menu to manage NIO Path in a Viewer. */
-public class FsContextMenu extends Shell {
-       private static final long serialVersionUID = -9120261153509855795L;
-
-       private final static CmsLog log = CmsLog.getLog(FsContextMenu.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_DELETE = "delete";
-       public final static String ACTION_ID_UPLOAD_FILE = "uploadFiles";
-       public final static String ACTION_ID_OPEN = "open";
-
-       // Local context
-       private final CmsFsBrowser browser;
-       // private final Viewer viewer;
-       private final static String KEY_ACTION_ID = "actionId";
-       private final static String[] DEFAULT_ACTIONS = { ACTION_ID_CREATE_FOLDER, ACTION_ID_BOOKMARK_FOLDER,
-                       ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_DELETE, ACTION_ID_UPLOAD_FILE,
-                       ACTION_ID_OPEN };
-       private Map<String, Button> actionButtons = new HashMap<String, Button>();
-
-       private Path currFolderPath;
-
-       public FsContextMenu(CmsFsBrowser browser) { // Viewer viewer, Display
-                                                                                                       // display) {
-               super(browser.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
-               this.browser = browser;
-               setLayout(EclipseUiUtils.noSpaceGridLayout());
-
-               Composite boxCmp = new Composite(this, SWT.NO_FOCUS | SWT.BORDER);
-               boxCmp.setLayout(EclipseUiUtils.noSpaceGridLayout());
-               CmsSwtUtils.style(boxCmp, FsStyles.CONTEXT_MENU_BOX);
-               createContextMenu(boxCmp);
-
-               addShellListener(new ActionsShellListener());
-       }
-
-       protected void createContextMenu(Composite boxCmp) {
-               ActionsSelListener asl = new ActionsSelListener();
-               for (String actionId : DEFAULT_ACTIONS) {
-                       Button btn = new Button(boxCmp, SWT.FLAT | SWT.PUSH | SWT.LEAD);
-                       btn.setText(getLabel(actionId));
-                       btn.setLayoutData(EclipseUiUtils.fillWidth());
-                       CmsSwtUtils.markup(btn);
-                       CmsSwtUtils.style(btn, actionId + FsStyles.BUTTON_SUFFIX);
-                       btn.setData(KEY_ACTION_ID, actionId);
-                       btn.addSelectionListener(asl);
-                       actionButtons.put(actionId, btn);
-               }
-       }
-
-       protected 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_DELETE:
-                       return "Delete";
-               case ACTION_ID_UPLOAD_FILE:
-                       return "Upload Files";
-               case ACTION_ID_OPEN:
-                       return "Open";
-               default:
-                       throw new IllegalArgumentException("Unknown action ID " + actionId);
-               }
-       }
-
-       protected void aboutToShow(Control source, Point location) {
-               IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
-               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);
-                       setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_DELETE, ACTION_ID_OPEN,
-                                       // to be implemented
-                                       ACTION_ID_BOOKMARK_FOLDER);
-               } else if (multiSel) {
-                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_DELETE);
-                       setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_OPEN,
-                                       // to be implemented
-                                       ACTION_ID_BOOKMARK_FOLDER);
-               } else if (isFolder) {
-                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_DELETE);
-                       setVisible(false, ACTION_ID_OPEN,
-                                       // to be implemented
-                                       ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER, ACTION_ID_BOOKMARK_FOLDER);
-               } else {
-                       setVisible(true, ACTION_ID_CREATE_FOLDER, ACTION_ID_UPLOAD_FILE, ACTION_ID_OPEN, ACTION_ID_DELETE);
-                       setVisible(false, ACTION_ID_SHARE_FOLDER, ACTION_ID_DOWNLOAD_FOLDER,
-                                       // to be implemented
-                                       ACTION_ID_BOOKMARK_FOLDER);
-               }
-       }
-
-       private 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, Path currFolderPath) {
-               if (isVisible())
-                       setVisible(false);
-               // 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;
-               aboutToShow(source, location);
-               pack();
-               layout();
-               if (source instanceof Control)
-                       setLocation(((Control) source).toDisplay(location.x, location.y));
-               open();
-       }
-
-       class StyleButton extends Label {
-               private static final long serialVersionUID = 7731102609123946115L;
-
-               public StyleButton(Composite parent, int swtStyle) {
-                       super(parent, swtStyle);
-               }
-
-       }
-
-       // class ActionsMouseListener extends MouseAdapter {
-       // private static final long serialVersionUID = -1041871937815812149L;
-       //
-       // @Override
-       // public void mouseDown(MouseEvent e) {
-       // Object eventSource = e.getSource();
-       // if (e.button == 1) {
-       // if (eventSource instanceof Button) {
-       // Button pressedBtn = (Button) eventSource;
-       // String actionId = (String) pressedBtn.getData(KEY_ACTION_ID);
-       // switch (actionId) {
-       // case ACTION_ID_CREATE_FOLDER:
-       // createFolder();
-       // break;
-       // case ACTION_ID_DELETE:
-       // deleteItems();
-       // 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";
-       // // case ACTION_ID_UPLOAD_FILE:
-       // // return "Upload Files";
-       // // case ACTION_ID_OPEN:
-       // // return "Open";
-       // }
-       // }
-       // }
-       // viewer.getControl().setFocus();
-       // // setVisible(false);
-       // }
-       // }
-
-       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;
-                               String actionId = (String) pressedBtn.getData(KEY_ACTION_ID);
-                               switch (actionId) {
-                               case ACTION_ID_CREATE_FOLDER:
-                                       createFolder();
-                                       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";
-                                       // case ACTION_ID_OPEN:
-                                       // return "Open";
-                               }
-                       }
-                       browser.setFocus();
-                       // viewer.getControl().setFocus();
-                       // setVisible(false);
-
-               }
-       }
-
-       class ActionsShellListener extends org.eclipse.swt.events.ShellAdapter {
-               private static final long serialVersionUID = -5092341449523150827L;
-
-               @Override
-               public void shellDeactivated(ShellEvent e) {
-                       setVisible(false);
-               }
-       }
-
-       private void openFile() {
-               log.warn("Implement single sourced, workbench independant \"Open File\" action");
-       }
-
-       private void deleteItems() {
-               IStructuredSelection selection = ((IStructuredSelection) browser.getViewer().getSelection());
-               if (selection.isEmpty())
-                       return;
-
-               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 (MessageDialog.openConfirm(this, "Confirm deletion", msg)) {
-                       for (Path path : paths) {
-                               try {
-                                       // Might have already been deleted if we are in a tree
-                                       Files.deleteIfExists(path);
-                               } catch (IOException e) {
-                                       throw new CmsException("Cannot delete path " + path, e);
-                               }
-                       }
-                       browser.refresh();
-               }
-       }
-
-       private void createFolder() {
-               String msg = "Please provide a name.";
-               String name = SingleValue.ask("Create folder", msg);
-               // TODO enhance check of name validity
-               if (EclipseUiUtils.notEmpty(name)) {
-                       try {
-                               Path child = currFolderPath.resolve(name);
-                               if (Files.exists(child))
-                                       throw new CmsException("An item with name " + name + " already exists at "
-                                                       + currFolderPath.toString() + ", cannot create");
-                               else
-                                       Files.createDirectories(child);
-                               browser.refresh();
-                       } catch (IOException e) {
-                               throw new CmsException("Cannot create folder " + name + " at " + currFolderPath.toString(), e);
-                       }
-               }
-       }
-
-       private void uploadFiles() {
-               try {
-                       FileDialog dialog = new FileDialog(browser.getShell(), 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;
-                               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)) {
-                                                               MessageDialog.openError(browser.getShell(), "Unimplemented directory import",
-                                                                               "Upload of directories in the system is not yet implemented");
-                                                               continue loop;
-                                                       }
-                                                       Path targetPath = currFolderPath.resolve(tmpPath.getFileName().toString());
-                                                       InputStream in = null;
-                                                       try {
-                                                               in = new ByteArrayInputStream(Files.readAllBytes(tmpPath));
-                                                               Files.copy(in, targetPath);
-                                                               Files.delete(tmpPath);
-                                                       } finally {
-                                                               IOUtils.closeQuietly(in);
-                                                       }
-                                                       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";
-                                                       MessageDialog.openError(browser.getShell(), "Missing file", msg);
-                                                       continue loop;
-                                               }
-                                       }
-                                       browser.refresh();
-                               }
-                       }
-               } catch (Exception e) {
-                       e.printStackTrace();
-                       MessageDialog.openError(getShell(), "Upload has failed", "Cannot import files to " + currFolderPath);
-               }
-       }
-
-       public void setCurrFolderPath(Path currFolderPath) {
-               this.currFolderPath = currFolderPath;
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FsStyles.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/FsStyles.java
deleted file mode 100644 (file)
index 9ae3192..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.argeo.cms.ui.fs;
-
-/** FS Ui specific CSS styles */
-public interface FsStyles {
-       String BREAD_CRUMB_BTN = "breadCrumb_btn";
-       String CONTEXT_MENU_BOX = "contextMenu_box";
-       String BUTTON_SUFFIX = "_btn";
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/package-info.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/fs/package-info.java
deleted file mode 100644 (file)
index 6a6c272..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** SWT/JFace file system components. */
-package org.argeo.cms.ui.fs;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/Activator.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/Activator.java
deleted file mode 100644 (file)
index e10da3a..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.argeo.cms.ui.internal;
-
-import org.argeo.api.cms.CmsState;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.util.tracker.ServiceTracker;
-
-public class Activator implements BundleActivator {
-
-       // avoid dependency to RWT OSGi
-       private final static String CONTEXT_NAME_PROP = "contextName";
-
-       private static ServiceTracker<CmsState, CmsState> nodeState;
-
-       // @Override
-       public void start(BundleContext bc) throws Exception {
-               // UI
-//             bc.registerService(ApplicationConfiguration.class, new MaintenanceUi(),
-//                             LangUtils.dico(CONTEXT_NAME_PROP, "system"));
-//             bc.registerService(ApplicationConfiguration.class, new UserUi(), LangUtils.dico(CONTEXT_NAME_PROP, "user"));
-
-               nodeState = new ServiceTracker<>(bc, CmsState.class, null);
-               nodeState.open();
-       }
-
-       @Override
-       public void stop(BundleContext context) throws Exception {
-               if (nodeState != null) {
-                       nodeState.close();
-                       nodeState = null;
-               }
-       }
-
-       public static CmsState getNodeState() {
-               return nodeState.getService();
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/JcrContentProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/JcrContentProvider.java
deleted file mode 100644 (file)
index ea0abdf..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.argeo.cms.ui.internal;
-
-import java.util.ArrayList;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsException;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.Viewer;
-
-@Deprecated
-class JcrContentProvider implements ITreeContentProvider {
-       private static final long serialVersionUID = -1333678161322488674L;
-
-       @Override
-       public void dispose() {
-       }
-
-       @Override
-       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-               if (newInput == null)
-                       return;
-               if (!(newInput instanceof Node))
-                       throw new CmsException("Input " + newInput + " must be a node");
-       }
-
-       @Override
-       public Object[] getElements(Object inputElement) {
-               try {
-                       Node node = (Node) inputElement;
-                       ArrayList<Node> arr = new ArrayList<Node>();
-                       NodeIterator nit = node.getNodes();
-                       while (nit.hasNext()) {
-                               arr.add(nit.nextNode());
-                       }
-                       return arr.toArray();
-               } catch (RepositoryException e) {
-                       throw new CmsException("Cannot get elements", e);
-               }
-       }
-
-       @Override
-       public Object[] getChildren(Object parentElement) {
-               try {
-                       Node node = (Node) parentElement;
-                       ArrayList<Node> arr = new ArrayList<Node>();
-                       NodeIterator nit = node.getNodes();
-                       while (nit.hasNext()) {
-                               arr.add(nit.nextNode());
-                       }
-                       return arr.toArray();
-               } catch (RepositoryException e) {
-                       throw new CmsException("Cannot get elements", e);
-               }
-       }
-
-       @Override
-       public Object getParent(Object element) {
-               try {
-                       Node node = (Node) element;
-                       if (node.getName().equals(""))
-                               return null;
-                       else
-                               return node.getParent();
-               } catch (RepositoryException e) {
-                       throw new CmsException("Cannot get elements", e);
-               }
-       }
-
-       @Override
-       public boolean hasChildren(Object element) {
-               try {
-                       Node node = (Node) element;
-                       return node.hasNodes();
-               } catch (RepositoryException e) {
-                       throw new CmsException("Cannot get elements", e);
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/JcrFileUploadReceiver.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/JcrFileUploadReceiver.java
deleted file mode 100644 (file)
index 60bb42b..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-package org.argeo.cms.ui.internal;
-
-import static javax.jcr.nodetype.NodeType.NT_FILE;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-
-import org.apache.commons.io.FilenameUtils;
-import org.argeo.api.cms.ux.CmsImageManager;
-import org.argeo.cms.ui.widgets.Img;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.rap.fileupload.FileDetails;
-import org.eclipse.rap.fileupload.FileUploadReceiver;
-
-public class JcrFileUploadReceiver extends FileUploadReceiver {
-       private Img img;
-       private final Node parentNode;
-       private final String nodeName;
-       private final CmsImageManager imageManager;
-
-       /** If nodeName is null, use the uploaded file name */
-       public JcrFileUploadReceiver(Img img, Node parentNode, String nodeName, CmsImageManager imageManager) {
-               super();
-               this.img = img;
-               this.parentNode = parentNode;
-               this.nodeName = nodeName;
-               this.imageManager = imageManager;
-       }
-
-       @Override
-       public void receive(InputStream stream, FileDetails details) throws IOException {
-               try {
-                       String fileName = nodeName != null ? nodeName : details.getFileName();
-                       String contentType = details.getContentType();
-                       if (isImage(details.getFileName(), contentType)) {
-                               imageManager.uploadImage(img.getNode(),parentNode, fileName, stream, contentType);
-                               return;
-                       }
-
-                       Node fileNode;
-                       if (parentNode.hasNode(fileName)) {
-                               fileNode = parentNode.getNode(fileName);
-                               if (!fileNode.isNodeType(NT_FILE))
-                                       fileNode.remove();
-                       }
-                       fileNode = JcrUtils.copyStreamAsFile(parentNode, fileName, stream);
-
-                       if (contentType != null) {
-                               fileNode.addMixin(NodeType.MIX_MIMETYPE);
-                               fileNode.setProperty(Property.JCR_MIMETYPE, contentType);
-                       }
-                       processNewFile(fileNode);
-                       fileNode.getSession().save();
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot receive " + details, e);
-               }
-       }
-
-       protected Boolean isImage(String fileName, String contentType) {
-               String ext = FilenameUtils.getExtension(fileName);
-               return ext != null && (ext.equals("png") || ext.equalsIgnoreCase("jpg"));
-       }
-
-       protected void processNewFile(Node node) {
-
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/SimpleEditableImage.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/internal/SimpleEditableImage.java
deleted file mode 100644 (file)
index 5e938d8..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.argeo.cms.ui.internal;
-
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.ux.Cms2DSize;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.widgets.EditableImage;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Text;
-
-/** NOT working yet. */
-public class SimpleEditableImage extends EditableImage {
-       private static final long serialVersionUID = -5689145523114022890L;
-
-       private String src;
-       private Cms2DSize imageSize;
-
-       public SimpleEditableImage(Composite parent, int swtStyle) {
-               super(parent, swtStyle);
-               // load(getControl());
-               getParent().layout();
-       }
-
-       public SimpleEditableImage(Composite parent, int swtStyle, String src, Cms2DSize imageSize) {
-               super(parent, swtStyle);
-               this.src = src;
-               this.imageSize = imageSize;
-       }
-
-       @Override
-       protected Control createControl(Composite box, String style) {
-               if (isEditing()) {
-                       return createText(box, style);
-               } else {
-                       return createLabel(box, style);
-               }
-       }
-
-       protected String createImgTag() throws RepositoryException {
-               String imgTag;
-               if (src != null)
-                       imgTag = CmsUiUtils.img(src, imageSize);
-               else
-                       imgTag = CmsUiUtils.noImg(imageSize != null ? imageSize : NO_IMAGE_SIZE);
-               return imgTag;
-       }
-
-       protected Text createText(Composite box, String style) {
-               Text text = new Text(box, getStyle());
-               CmsSwtUtils.style(text, style);
-               return text;
-       }
-
-       public String getSrc() {
-               return src;
-       }
-
-       public void setSrc(String src) {
-               this.src = src;
-       }
-
-       public Cms2DSize getImageSize() {
-               return imageSize;
-       }
-
-       public void setImageSize(Cms2DSize imageSize) {
-               this.imageSize = imageSize;
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/DefaultRepositoryRegister.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/DefaultRepositoryRegister.java
deleted file mode 100644 (file)
index 3806341..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.Observable;
-import java.util.TreeMap;
-
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsLog;
-
-public class DefaultRepositoryRegister extends Observable implements RepositoryRegister {
-       /** Key for a JCR repository alias */
-       private final static String CN = CmsConstants.CN;
-       /** Key for a JCR repository URI */
-       // public final static String JCR_REPOSITORY_URI = "argeo.jcr.repository.uri";
-       private final static CmsLog log = CmsLog.getLog(DefaultRepositoryRegister.class);
-
-       /** Read only map which will be directly exposed. */
-       private Map<String, Repository> repositories = Collections.unmodifiableMap(new TreeMap<String, Repository>());
-
-       @SuppressWarnings("rawtypes")
-       public synchronized Repository getRepository(Map parameters) throws RepositoryException {
-               if (!parameters.containsKey(CN))
-                       throw new RepositoryException("Parameter " + CN + " has to be defined.");
-               String alias = parameters.get(CN).toString();
-               if (!repositories.containsKey(alias))
-                       throw new RepositoryException("No repository registered with alias " + alias);
-
-               return repositories.get(alias);
-       }
-
-       /** Access to the read-only map */
-       public synchronized Map<String, Repository> getRepositories() {
-               return repositories;
-       }
-
-       /** Registers a service, typically called when OSGi services are bound. */
-       @SuppressWarnings("rawtypes")
-       public synchronized void register(Repository repository, Map properties) {
-               String alias;
-               if (properties == null || !properties.containsKey(CN)) {
-                       log.warn("Cannot register a repository if no " + CN + " property is specified.");
-                       return;
-               }
-               alias = properties.get(CN).toString();
-               Map<String, Repository> map = new TreeMap<String, Repository>(repositories);
-               map.put(alias, repository);
-               repositories = Collections.unmodifiableMap(map);
-               setChanged();
-               notifyObservers(alias);
-       }
-
-       /** Unregisters a service, typically called when OSGi services are unbound. */
-       @SuppressWarnings("rawtypes")
-       public synchronized void unregister(Repository repository, Map properties) {
-               // TODO: also check bean name?
-               if (properties == null || !properties.containsKey(CN)) {
-                       log.warn("Cannot unregister a repository without property " + CN);
-                       return;
-               }
-
-               String alias = properties.get(CN).toString();
-               Map<String, Repository> map = new TreeMap<String, Repository>(repositories);
-               if (map.remove(alias) == null) {
-                       log.warn("No repository was registered with alias " + alias);
-                       return;
-               }
-               repositories = Collections.unmodifiableMap(map);
-               setChanged();
-               notifyObservers(alias);
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/FullVersioningTreeContentProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/FullVersioningTreeContentProvider.java
deleted file mode 100644 (file)
index 0f7ee77..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-import javax.jcr.version.VersionIterator;
-import javax.jcr.version.VersionManager;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.Viewer;
-
-/**
- * Display some version information of a JCR full versionable node in a tree
- * like structure
- */
-public class FullVersioningTreeContentProvider implements ITreeContentProvider {
-       private static final long serialVersionUID = 8691772509491211112L;
-
-       /**
-        * Sends back the first level of the Tree. input element must be a single
-        * node object
-        */
-       public Object[] getElements(Object inputElement) {
-               try {
-                       Node rootNode = (Node) inputElement;
-                       String curPath = rootNode.getPath();
-                       VersionManager vm = rootNode.getSession().getWorkspace()
-                                       .getVersionManager();
-
-                       VersionHistory vh = vm.getVersionHistory(curPath);
-                       List<Version> result = new ArrayList<Version>();
-                       VersionIterator vi = vh.getAllLinearVersions();
-
-                       while (vi.hasNext()) {
-                               result.add(vi.nextVersion());
-                       }
-                       return result.toArray();
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException(
-                                       "Unexpected error while getting version elements", re);
-               }
-       }
-
-       public Object[] getChildren(Object parentElement) {
-               try {
-                       if (parentElement instanceof Version) {
-                               List<Node> tmp = new ArrayList<Node>();
-                               tmp.add(((Version) parentElement).getFrozenNode());
-                               return tmp.toArray();
-                       }
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Unexpected error while getting child "
-                                       + "node for version element", re);
-               }
-               return null;
-       }
-
-       public Object getParent(Object element) {
-               try {
-                       // this will not work in a simpleVersionning environment, parent is
-                       // not a node.
-                       if (element instanceof Node
-                                       && ((Node) element).isNodeType(NodeType.NT_FROZEN_NODE)) {
-                               Node node = (Node) element;
-                               return node.getParent();
-                       } else
-                               return null;
-               } catch (RepositoryException e) {
-                       return null;
-               }
-       }
-
-       public boolean hasChildren(Object element) {
-               try {
-                       if (element instanceof Version)
-                               return true;
-                       else if (element instanceof Node)
-                               return ((Node) element).hasNodes();
-                       else
-                               return false;
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot check children of " + element, e);
-               }
-       }
-
-       public void dispose() {
-       }
-
-       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/JcrBrowserUtils.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/JcrBrowserUtils.java
deleted file mode 100644 (file)
index b36acc3..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.ui.jcr.model.RepositoriesElem;
-import org.argeo.cms.ui.jcr.model.RepositoryElem;
-import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
-import org.argeo.cms.ui.jcr.model.WorkspaceElem;
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.argeo.eclipse.ui.EclipseUiException;
-
-/** Useful methods to manage the JCR Browser */
-public class JcrBrowserUtils {
-
-       public static String getPropertyTypeAsString(Property prop) {
-               try {
-                       return PropertyType.nameFromValue(prop.getType());
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot check type for " + prop, e);
-               }
-       }
-
-       /** Insure that the UI component is not stale, refresh if needed */
-       public static void forceRefreshIfNeeded(TreeParent element) {
-               Node curNode = null;
-
-               boolean doRefresh = false;
-
-               try {
-                       if (element instanceof SingleJcrNodeElem) {
-                               curNode = ((SingleJcrNodeElem) element).getNode();
-                       } else if (element instanceof WorkspaceElem) {
-                               curNode = ((WorkspaceElem) element).getRootNode();
-                       }
-
-                       if (curNode != null && element.getChildren().length != curNode.getNodes().getSize())
-                               doRefresh = true;
-                       else if (element instanceof RepositoryElem) {
-                               RepositoryElem rn = (RepositoryElem) element;
-                               if (rn.isConnected()) {
-                                       String[] wkpNames = rn.getAccessibleWorkspaceNames();
-                                       if (element.getChildren().length != wkpNames.length)
-                                               doRefresh = true;
-                               }
-                       } else if (element instanceof RepositoriesElem) {
-                               doRefresh = true;
-                               // Always force refresh for RepositoriesElem : the condition
-                               // below does not take remote repository into account and it is
-                               // not trivial to do so.
-
-                               // RepositoriesElem rn = (RepositoriesElem) element;
-                               // if (element.getChildren().length !=
-                               // rn.getRepositoryRegister()
-                               // .getRepositories().size())
-                               // doRefresh = true;
-                       }
-                       if (doRefresh) {
-                               element.clearChildren();
-                               element.getChildren();
-                       }
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Unexpected error while synchronising the UI with the JCR repository", re);
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/JcrDClickListener.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/JcrDClickListener.java
deleted file mode 100644 (file)
index 1707681..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.ui.jcr.model.RepositoryElem;
-import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
-import org.argeo.cms.ui.jcr.model.WorkspaceElem;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.TreeViewer;
-
-/** Centralizes the management of double click on a NodeTreeViewer */
-public class JcrDClickListener implements IDoubleClickListener {
-       // private final static Log log = LogFactory
-       // .getLog(GenericNodeDoubleClickListener.class);
-
-       private TreeViewer nodeViewer;
-
-       // private JcrFileProvider jfp;
-       // private FileHandler fileHandler;
-
-       public JcrDClickListener(TreeViewer nodeViewer) {
-               this.nodeViewer = nodeViewer;
-               // jfp = new JcrFileProvider();
-               // Commented out. see https://www.argeo.org/bugzilla/show_bug.cgi?id=188
-               // fileHandler = null;
-               // fileHandler = new FileHandler(jfp);
-       }
-
-       public void doubleClick(DoubleClickEvent event) {
-               if (event.getSelection() == null || event.getSelection().isEmpty())
-                       return;
-               Object obj = ((IStructuredSelection) event.getSelection()).getFirstElement();
-               if (obj instanceof RepositoryElem) {
-                       RepositoryElem rpNode = (RepositoryElem) obj;
-                       if (rpNode.isConnected()) {
-                               rpNode.logout();
-                       } else {
-                               rpNode.login();
-                       }
-                       nodeViewer.refresh(obj);
-               } else if (obj instanceof WorkspaceElem) {
-                       WorkspaceElem wn = (WorkspaceElem) obj;
-                       if (wn.isConnected())
-                               wn.logout();
-                       else
-                               wn.login();
-                       nodeViewer.refresh(obj);
-               } else if (obj instanceof SingleJcrNodeElem) {
-                       SingleJcrNodeElem sjn = (SingleJcrNodeElem) obj;
-                       Node node = sjn.getNode();
-                       openNode(node);
-               }
-       }
-
-       protected void openNode(Node node) {
-               // TODO implement generic behaviour
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/JcrImages.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/JcrImages.java
deleted file mode 100644 (file)
index d1d1e31..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import org.argeo.cms.ui.theme.CmsImages;
-import org.eclipse.swt.graphics.Image;
-
-/** Shared icons. */
-public class JcrImages {
-       public final static Image NODE = CmsImages.createIcon("node.gif");
-       public final static Image FOLDER = CmsImages.createIcon("folder.gif");
-       public final static Image FILE = CmsImages.createIcon("file.gif");
-       public final static Image BINARY = CmsImages.createIcon("binary.png");
-       public final static Image HOME = CmsImages.createIcon("person-logged-in.png");
-       public final static Image SORT = CmsImages.createIcon("sort.gif");
-       public final static Image REMOVE = CmsImages.createIcon("remove.gif");
-
-       public final static Image REPOSITORIES = CmsImages.createIcon("repositories.gif");
-       public final static Image REPOSITORY_DISCONNECTED = CmsImages.createIcon("repository_disconnected.gif");
-       public final static Image REPOSITORY_CONNECTED = CmsImages.createIcon("repository_connected.gif");
-       public final static Image REMOTE_DISCONNECTED = CmsImages.createIcon("remote_disconnected.gif");
-       public final static Image REMOTE_CONNECTED = CmsImages.createIcon("remote_connected.gif");
-       public final static Image WORKSPACE_DISCONNECTED = CmsImages.createIcon("workspace_disconnected.png");
-       public final static Image WORKSPACE_CONNECTED = CmsImages.createIcon("workspace_connected.png");
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/JcrTreeContentProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/JcrTreeContentProvider.java
deleted file mode 100644 (file)
index cc8479f..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.jcr.util.JcrItemsComparator;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.Viewer;
-
-/**
- * Implementation of the {@code ITreeContentProvider} in order to display a
- * single JCR node and its children in a tree like structure
- */
-public class JcrTreeContentProvider implements ITreeContentProvider {
-       private static final long serialVersionUID = -2128326504754297297L;
-       // private Node rootNode;
-       private JcrItemsComparator itemComparator = new JcrItemsComparator();
-
-       /**
-        * Sends back the first level of the Tree. input element must be a single node
-        * object
-        */
-       public Object[] getElements(Object inputElement) {
-               Node rootNode = (Node) inputElement;
-               return childrenNodes(rootNode);
-       }
-
-       public Object[] getChildren(Object parentElement) {
-               return childrenNodes((Node) parentElement);
-       }
-
-       public Object getParent(Object element) {
-               try {
-                       Node node = (Node) element;
-                       if (!node.getPath().equals("/"))
-                               return node.getParent();
-                       else
-                               return null;
-               } catch (RepositoryException e) {
-                       return null;
-               }
-       }
-
-       public boolean hasChildren(Object element) {
-               try {
-                       return ((Node) element).hasNodes();
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot check children existence on " + element, e);
-               }
-       }
-
-       protected Object[] childrenNodes(Node parentNode) {
-               try {
-                       List<Node> children = new ArrayList<Node>();
-                       NodeIterator nit = parentNode.getNodes();
-                       while (nit.hasNext()) {
-                               Node node = nit.nextNode();
-//                             if (node.getName().startsWith("rep:") || node.getName().startsWith("jcr:")
-//                                             || node.getName().startsWith("nt:"))
-//                                     continue nodes;
-                               children.add(node);
-                       }
-                       Node[] arr = children.toArray(new Node[0]);
-                       Arrays.sort(arr, itemComparator);
-                       return arr;
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot list children of " + parentNode, e);
-               }
-       }
-
-       public void dispose() {
-       }
-
-       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/NodeContentProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/NodeContentProvider.java
deleted file mode 100644 (file)
index 0625cc8..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.RepositoryFactory;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.security.Keyring;
-import org.argeo.cms.ui.jcr.model.RepositoriesElem;
-import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.Viewer;
-
-/**
- * Implementation of the {@code ITreeContentProvider} to display multiple
- * repository environment in a tree like structure
- */
-public class NodeContentProvider implements ITreeContentProvider {
-       private static final long serialVersionUID = -4083809398848374403L;
-       final private RepositoryRegister repositoryRegister;
-       final private RepositoryFactory repositoryFactory;
-
-       // Current user session on the default workspace of the argeo Node
-       final private Session userSession;
-       final private Keyring keyring;
-       private boolean sortChildren;
-
-       // Reference for cleaning
-       private SingleJcrNodeElem homeNode = null;
-       private RepositoriesElem repositoriesNode = null;
-
-       // Utils
-       private TreeBrowserComparator itemComparator = new TreeBrowserComparator();
-
-       public NodeContentProvider(Session userSession, Keyring keyring,
-                       RepositoryRegister repositoryRegister,
-                       RepositoryFactory repositoryFactory, Boolean sortChildren) {
-               this.userSession = userSession;
-               this.keyring = keyring;
-               this.repositoryRegister = repositoryRegister;
-               this.repositoryFactory = repositoryFactory;
-               this.sortChildren = sortChildren;
-       }
-
-       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-               if (newInput == null)// dispose
-                       return;
-
-               if (userSession != null) {
-                       Node userHome = CmsJcrUtils.getUserHome(userSession);
-                       if (userHome != null) {
-                               // TODO : find a way to dynamically get alias for the node
-                               if (homeNode != null)
-                                       homeNode.dispose();
-                               homeNode = new SingleJcrNodeElem(null, userHome,
-                                               userSession.getUserID(), CmsConstants.EGO_REPOSITORY);
-                       }
-               }
-               if (repositoryRegister != null) {
-                       if (repositoriesNode != null)
-                               repositoriesNode.dispose();
-                       repositoriesNode = new RepositoriesElem("Repositories",
-                                       repositoryRegister, repositoryFactory, null, userSession,
-                                       keyring);
-               }
-       }
-
-       /**
-        * Sends back the first level of the Tree. Independent from inputElement
-        * that can be null
-        */
-       public Object[] getElements(Object inputElement) {
-               List<Object> objs = new ArrayList<Object>();
-               if (homeNode != null)
-                       objs.add(homeNode);
-               if (repositoriesNode != null)
-                       objs.add(repositoriesNode);
-               return objs.toArray();
-       }
-
-       public Object[] getChildren(Object parentElement) {
-               if (parentElement instanceof TreeParent) {
-                       if (sortChildren) {
-                               Object[] tmpArr = ((TreeParent) parentElement).getChildren();
-                               if (tmpArr == null)
-                                       return new Object[0];
-                               TreeParent[] arr = new TreeParent[tmpArr.length];
-                               for (int i = 0; i < tmpArr.length; i++)
-                                       arr[i] = (TreeParent) tmpArr[i];
-                               Arrays.sort(arr, itemComparator);
-                               return arr;
-                       } else
-                               return ((TreeParent) parentElement).getChildren();
-               } else
-                       return new Object[0];
-       }
-
-       /**
-        * Sets whether the content provider should order the children nodes or not.
-        * It is user duty to call a full refresh of the tree after changing this
-        * parameter.
-        */
-       public void setSortChildren(boolean sortChildren) {
-               this.sortChildren = sortChildren;
-       }
-
-       public Object getParent(Object element) {
-               if (element instanceof TreeParent) {
-                       return ((TreeParent) element).getParent();
-               } else
-                       return null;
-       }
-
-       public boolean hasChildren(Object element) {
-               if (element instanceof RepositoriesElem) {
-                       RepositoryRegister rr = ((RepositoriesElem) element)
-                                       .getRepositoryRegister();
-                       return rr.getRepositories().size() > 0;
-               } else if (element instanceof TreeParent) {
-                       TreeParent tp = (TreeParent) element;
-                       return tp.hasChildren();
-               }
-               return false;
-       }
-
-       public void dispose() {
-               if (homeNode != null)
-                       homeNode.dispose();
-               if (repositoriesNode != null) {
-                       // logs out open sessions
-                       // see https://bugzilla.argeo.org/show_bug.cgi?id=23
-                       repositoriesNode.dispose();
-               }
-       }
-
-       /**
-        * Specific comparator for this view. See specification here:
-        * https://www.argeo.org/bugzilla/show_bug.cgi?id=139
-        */
-       private class TreeBrowserComparator implements Comparator<TreeParent> {
-
-               public int category(TreeParent element) {
-                       if (element instanceof SingleJcrNodeElem) {
-                               Node node = ((SingleJcrNodeElem) element).getNode();
-                               try {
-                                       if (node.isNodeType(NodeType.NT_FOLDER))
-                                               return 5;
-                               } catch (RepositoryException e) {
-                                       // TODO Auto-generated catch block
-                                       e.printStackTrace();
-                               }
-                       }
-                       return 10;
-               }
-
-               public int compare(TreeParent o1, TreeParent o2) {
-                       int cat1 = category(o1);
-                       int cat2 = category(o2);
-
-                       if (cat1 != cat2) {
-                               return cat1 - cat2;
-                       }
-                       return o1.getName().compareTo(o2.getName());
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/NodeLabelProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/NodeLabelProvider.java
deleted file mode 100644 (file)
index a5751c0..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import javax.jcr.NamespaceException;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.ui.jcr.model.RemoteRepositoryElem;
-import org.argeo.cms.ui.jcr.model.RepositoriesElem;
-import org.argeo.cms.ui.jcr.model.RepositoryElem;
-import org.argeo.cms.ui.jcr.model.SingleJcrNodeElem;
-import org.argeo.cms.ui.jcr.model.WorkspaceElem;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.swt.graphics.Image;
-
-/** Provides reasonable defaults for know JCR types. */
-public class NodeLabelProvider extends ColumnLabelProvider {
-       private static final long serialVersionUID = -3662051696443321843L;
-
-       private final static CmsLog log = CmsLog.getLog(NodeLabelProvider.class);
-
-       public String getText(Object element) {
-               try {
-                       if (element instanceof SingleJcrNodeElem) {
-                               SingleJcrNodeElem sjn = (SingleJcrNodeElem) element;
-                               return getText(sjn.getNode());
-                       } else if (element instanceof Node) {
-                               return getText((Node) element);
-                       } else
-                               return super.getText(element);
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Unexpected JCR error while getting node name.");
-               }
-       }
-
-       protected String getText(Node node) throws RepositoryException {
-               String label = node.getName();
-               StringBuffer mixins = new StringBuffer("");
-               for (NodeType type : node.getMixinNodeTypes())
-                       mixins.append(' ').append(type.getName());
-
-               return label + " [" + node.getPrimaryNodeType().getName() + mixins + "]";
-       }
-
-       @Override
-       public Image getImage(Object element) {
-               if (element instanceof RemoteRepositoryElem) {
-                       if (((RemoteRepositoryElem) element).isConnected())
-                               return JcrImages.REMOTE_CONNECTED;
-                       else
-                               return JcrImages.REMOTE_DISCONNECTED;
-               } else if (element instanceof RepositoryElem) {
-                       if (((RepositoryElem) element).isConnected())
-                               return JcrImages.REPOSITORY_CONNECTED;
-                       else
-                               return JcrImages.REPOSITORY_DISCONNECTED;
-               } else if (element instanceof WorkspaceElem) {
-                       if (((WorkspaceElem) element).isConnected())
-                               return JcrImages.WORKSPACE_CONNECTED;
-                       else
-                               return JcrImages.WORKSPACE_DISCONNECTED;
-               } else if (element instanceof RepositoriesElem) {
-                       return JcrImages.REPOSITORIES;
-               } else if (element instanceof SingleJcrNodeElem) {
-                       Node nodeElem = ((SingleJcrNodeElem) element).getNode();
-                       return getImage(nodeElem);
-
-                       // if (element instanceof Node) {
-                       // return getImage((Node) element);
-                       // } else if (element instanceof WrappedNode) {
-                       // return getImage(((WrappedNode) element).getNode());
-                       // } else if (element instanceof NodesWrapper) {
-                       // return getImage(((NodesWrapper) element).getNode());
-                       // }
-               }
-               // try {
-               // return super.getImage();
-               // } catch (RepositoryException e) {
-               // return null;
-               // }
-               return super.getImage(element);
-       }
-
-       protected Image getImage(Node node) {
-               try {
-                       if (node.getPrimaryNodeType().isNodeType(NodeType.NT_FILE))
-                               return JcrImages.FILE;
-                       else if (node.getPrimaryNodeType().isNodeType(NodeType.NT_FOLDER))
-                               return JcrImages.FOLDER;
-                       else if (node.getPrimaryNodeType().isNodeType(NodeType.NT_RESOURCE))
-                               return JcrImages.BINARY;
-                       try {
-                               // TODO check workspace type?
-                               if (node.getDepth() == 1 && node.hasProperty(Property.JCR_ID))
-                                       return JcrImages.HOME;
-
-                               // optimizes
-//                             if (node.hasProperty(LdapAttrs.uid.property()) && node.isNodeType(NodeTypes.NODE_USER_HOME))
-//                                     return JcrImages.HOME;
-                       } catch (NamespaceException e) {
-                               // node namespace is not registered in this repo
-                       }
-                       return JcrImages.NODE;
-               } catch (RepositoryException e) {
-                       log.warn("Error while retrieving type for " + node + " in order to display corresponding image");
-                       e.printStackTrace();
-                       return null;
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/OsgiRepositoryRegister.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/OsgiRepositoryRegister.java
deleted file mode 100644 (file)
index 444350a..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Repository;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-public class OsgiRepositoryRegister extends DefaultRepositoryRegister {
-       private final static BundleContext bc = FrameworkUtil.getBundle(OsgiRepositoryRegister.class).getBundleContext();
-       private final ServiceTracker<Repository, Repository> repositoryTracker;
-
-       public OsgiRepositoryRegister() {
-               repositoryTracker = new ServiceTracker<Repository, Repository>(bc, Repository.class, null) {
-
-                       @Override
-                       public Repository addingService(ServiceReference<Repository> reference) {
-
-                               Repository repository = super.addingService(reference);
-                               Map<String, Object> props = new HashMap<>();
-                               for (String key : reference.getPropertyKeys()) {
-                                       props.put(key, reference.getProperty(key));
-                               }
-                               register(repository, props);
-                               return repository;
-                       }
-
-                       @Override
-                       public void removedService(ServiceReference<Repository> reference, Repository service) {
-                               Map<String, Object> props = new HashMap<>();
-                               for (String key : reference.getPropertyKeys()) {
-                                       props.put(key, reference.getProperty(key));
-                               }
-                               unregister(service, props);
-                               super.removedService(reference, service);
-                       }
-
-               };
-       }
-
-       public void init() {
-               repositoryTracker.open();
-       }
-
-       public void destroy() {
-               repositoryTracker.close();
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/PropertiesContentProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/PropertiesContentProvider.java
deleted file mode 100644 (file)
index fd544bb..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import java.util.Set;
-import java.util.TreeSet;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.RepositoryException;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.jcr.util.JcrItemsComparator;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.Viewer;
-
-/** Simple content provider that displays all properties of a given Node */
-public class PropertiesContentProvider implements IStructuredContentProvider {
-       private static final long serialVersionUID = 5227554668841613078L;
-       private JcrItemsComparator itemComparator = new JcrItemsComparator();
-
-       public void dispose() {
-       }
-
-       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-       }
-
-       public Object[] getElements(Object inputElement) {
-               try {
-                       if (inputElement instanceof Node) {
-                               Set<Property> props = new TreeSet<Property>(itemComparator);
-                               PropertyIterator pit = ((Node) inputElement).getProperties();
-                               while (pit.hasNext())
-                                       props.add(pit.nextProperty());
-                               return props.toArray();
-                       }
-                       return new Object[] {};
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot get element for "
-                                       + inputElement, e);
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/PropertyLabelProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/PropertyLabelProvider.java
deleted file mode 100644 (file)
index 37b90f7..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-
-import javax.jcr.Property;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-
-import org.argeo.cms.ui.CmsUiConstants;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.jface.viewers.ViewerCell;
-
-/** Default basic label provider for a given JCR Node's properties */
-public class PropertyLabelProvider extends ColumnLabelProvider {
-       private static final long serialVersionUID = -5405794508731390147L;
-
-       // To be able to change column order easily
-       public static final int COLUMN_PROPERTY = 0;
-       public static final int COLUMN_VALUE = 1;
-       public static final int COLUMN_TYPE = 2;
-       public static final int COLUMN_ATTRIBUTES = 3;
-
-       // Utils
-       protected DateFormat timeFormatter = new SimpleDateFormat(CmsUiConstants.DATE_TIME_FORMAT);
-
-       public void update(ViewerCell cell) {
-               Object element = cell.getElement();
-               cell.setText(getColumnText(element, cell.getColumnIndex()));
-       }
-
-       public String getColumnText(Object element, int columnIndex) {
-               try {
-                       if (element instanceof Property) {
-                               Property prop = (Property) element;
-                               if (prop.isMultiple()) {
-                                       switch (columnIndex) {
-                                       case COLUMN_PROPERTY:
-                                               return prop.getName();
-                                       case COLUMN_VALUE:
-                                               // Corresponding values are listed on children
-                                               return "";
-                                       case COLUMN_TYPE:
-                                               return JcrBrowserUtils.getPropertyTypeAsString(prop);
-                                       case COLUMN_ATTRIBUTES:
-                                               return JcrUtils.getPropertyDefinitionAsString(prop);
-                                       }
-                               } else {
-                                       switch (columnIndex) {
-                                       case COLUMN_PROPERTY:
-                                               return prop.getName();
-                                       case COLUMN_VALUE:
-                                               return formatValueAsString(prop.getValue());
-                                       case COLUMN_TYPE:
-                                               return JcrBrowserUtils.getPropertyTypeAsString(prop);
-                                       case COLUMN_ATTRIBUTES:
-                                               return JcrUtils.getPropertyDefinitionAsString(prop);
-                                       }
-                               }
-                       } else if (element instanceof Value) {
-                               Value val = (Value) element;
-                               switch (columnIndex) {
-                               case COLUMN_PROPERTY:
-                                       // Nothing to show
-                                       return "";
-                               case COLUMN_VALUE:
-                                       return formatValueAsString(val);
-                               case COLUMN_TYPE:
-                                       // listed on the parent
-                                       return "";
-                               case COLUMN_ATTRIBUTES:
-                                       // Corresponding attributes are listed on the parent
-                                       return "";
-                               }
-                       }
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Cannot retrieve prop value on " + element, re);
-               }
-               return null;
-       }
-
-       private String formatValueAsString(Value value) {
-               // TODO enhance this method
-               try {
-                       String strValue;
-
-                       if (value.getType() == PropertyType.BINARY)
-                               strValue = "<binary>";
-                       else if (value.getType() == PropertyType.DATE)
-                               strValue = timeFormatter.format(value.getDate().getTime());
-                       else
-                               strValue = value.getString();
-                       return strValue;
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("unexpected error while formatting value", e);
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/RepositoryRegister.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/RepositoryRegister.java
deleted file mode 100644 (file)
index 802c756..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import java.util.Map;
-
-import javax.jcr.Repository;
-import javax.jcr.RepositoryFactory;
-
-/** Allows to register repositories by name. */
-public interface RepositoryRegister extends RepositoryFactory {
-       /**
-        * The registered {@link Repository} as a read-only map. Note that this
-        * method should be called for each access in order to be sure to be up to
-        * date in case repositories have registered/unregistered
-        */
-       public Map<String, Repository> getRepositories();
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/VersionLabelProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/VersionLabelProvider.java
deleted file mode 100644 (file)
index 37dfe2b..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.argeo.cms.ui.jcr;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.version.Version;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-
-/**
- * Simple wrapping of the ColumnLabelProvider class to provide text display in
- * order to build a tree for version. The getText() method does not assume that
- * {@link Version} extends {@link Node} class to respect JCR 2.0 specification
- * 
- */
-public class VersionLabelProvider extends ColumnLabelProvider {
-       private static final long serialVersionUID = 5270739851193688238L;
-
-       public String getText(Object element) {
-               try {
-                       if (element instanceof Version) {
-                               Version version = (Version) element;
-                               return version.getName();
-                       } else if (element instanceof Node) {
-                               return ((Node) element).getName();
-                       }
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException(
-                                       "Unexpected error while getting element name", re);
-               }
-               return super.getText(element);
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/MaintainedRepositoryElem.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/MaintainedRepositoryElem.java
deleted file mode 100644 (file)
index d33b33f..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.argeo.cms.ui.jcr.model;
-
-import javax.jcr.Repository;
-
-import org.argeo.cms.ux.widgets.TreeParent;
-
-/** Wrap a MaintainedRepository */
-public class MaintainedRepositoryElem extends RepositoryElem {
-
-       public MaintainedRepositoryElem(String alias, Repository repository, TreeParent parent) {
-               super(alias, repository, parent);
-               // if (!(repository instanceof MaintainedRepository)) {
-               // throw new ArgeoException("Repository " + alias
-               // + " is not a maintained repository");
-               // }
-       }
-
-       // protected MaintainedRepository getMaintainedRepository() {
-       // return (MaintainedRepository) getRepository();
-       // }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/RemoteRepositoryElem.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/RemoteRepositoryElem.java
deleted file mode 100644 (file)
index 908d1b1..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-package org.argeo.cms.ui.jcr.model;
-
-import java.util.Arrays;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.RepositoryFactory;
-import javax.jcr.Session;
-import javax.jcr.SimpleCredentials;
-
-import org.argeo.cms.ArgeoNames;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.security.Keyring;
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.argeo.eclipse.ui.EclipseUiException;
-
-/** Root of a remote repository */
-public class RemoteRepositoryElem extends RepositoryElem {
-       private final Keyring keyring;
-       /**
-        * A session of the logged in user on the default workspace of the node
-        * repository.
-        */
-       private final Session userSession;
-       private final String remoteNodePath;
-
-       private final RepositoryFactory repositoryFactory;
-       private final String uri;
-
-       public RemoteRepositoryElem(String alias, RepositoryFactory repositoryFactory, String uri, TreeParent parent,
-                       Session userSession, Keyring keyring, String remoteNodePath) {
-               super(alias, null, parent);
-               this.repositoryFactory = repositoryFactory;
-               this.uri = uri;
-               this.keyring = keyring;
-               this.userSession = userSession;
-               this.remoteNodePath = remoteNodePath;
-       }
-
-       @Override
-       protected Session repositoryLogin(String workspaceName) throws RepositoryException {
-               Node remoteRepository = userSession.getNode(remoteNodePath);
-               String userID = remoteRepository.getProperty(ArgeoNames.ARGEO_USER_ID).getString();
-               if (userID.trim().equals("")) {
-                       return getRepository().login(workspaceName);
-               } else {
-                       String pwdPath = remoteRepository.getPath() + '/' + ArgeoNames.ARGEO_PASSWORD;
-                       char[] password = keyring.getAsChars(pwdPath);
-                       try {
-                               SimpleCredentials credentials = new SimpleCredentials(userID, password);
-                               return getRepository().login(credentials, workspaceName);
-                       } finally {
-                               Arrays.fill(password, 0, password.length, ' ');
-                       }
-               }
-       }
-
-       @Override
-       public Repository getRepository() {
-               if (repository == null)
-                       repository = CmsJcrUtils.getRepositoryByUri(repositoryFactory, uri);
-               return super.getRepository();
-       }
-
-       public void remove() {
-               try {
-                       Node remoteNode = userSession.getNode(remoteNodePath);
-                       remoteNode.remove();
-                       remoteNode.getSession().save();
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot remove " + remoteNodePath, e);
-               }
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/RepositoriesElem.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/RepositoriesElem.java
deleted file mode 100644 (file)
index 742800b..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-package org.argeo.cms.ui.jcr.model;
-
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.RepositoryFactory;
-import javax.jcr.Session;
-
-import org.argeo.cms.ArgeoNames;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.security.Keyring;
-import org.argeo.cms.ui.jcr.RepositoryRegister;
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
-
-/**
- * UI Tree component that implements the Argeo abstraction of a
- * {@link RepositoryFactory} that enable a user to "mount" various repositories
- * in a single Tree like View. It is usually meant to be at the root of the UI
- * Tree and thus {@link getParent()} method will return null.
- * 
- * The {@link RepositoryFactory} is injected at instantiation time and must be
- * use get or register new {@link Repository} objects upon which a reference is
- * kept here.
- */
-
-public class RepositoriesElem extends TreeParent implements ArgeoNames {
-       private final RepositoryRegister repositoryRegister;
-       private final RepositoryFactory repositoryFactory;
-
-       /**
-        * A session of the logged in user on the default workspace of the node
-        * repository.
-        */
-       private final Session userSession;
-       private final Keyring keyring;
-
-       public RepositoriesElem(String name, RepositoryRegister repositoryRegister, RepositoryFactory repositoryFactory,
-                       TreeParent parent, Session userSession, Keyring keyring) {
-               super(name);
-               this.repositoryRegister = repositoryRegister;
-               this.repositoryFactory = repositoryFactory;
-               this.userSession = userSession;
-               this.keyring = keyring;
-       }
-
-       /**
-        * Override normal behavior to initialize the various repositories only at
-        * request time
-        */
-       @Override
-       public synchronized Object[] getChildren() {
-               if (isLoaded()) {
-                       return super.getChildren();
-               } else {
-                       // initialize current object
-                       Map<String, Repository> refRepos = repositoryRegister.getRepositories();
-                       for (String name : refRepos.keySet()) {
-                               Repository repository = refRepos.get(name);
-                               // if (repository instanceof MaintainedRepository)
-                               // super.addChild(new MaintainedRepositoryElem(name,
-                               // repository, this));
-                               // else
-                               super.addChild(new RepositoryElem(name, repository, this));
-                       }
-
-                       // remote
-                       if (keyring != null) {
-                               try {
-                                       addRemoteRepositories(keyring);
-                               } catch (RepositoryException e) {
-                                       throw new EclipseUiException("Cannot browse remote repositories", e);
-                               }
-                       }
-                       return super.getChildren();
-               }
-       }
-
-       protected void addRemoteRepositories(Keyring jcrKeyring) throws RepositoryException {
-               Node userHome = CmsJcrUtils.getUserHome(userSession);
-               if (userHome != null && userHome.hasNode(ARGEO_REMOTE)) {
-                       NodeIterator it = userHome.getNode(ARGEO_REMOTE).getNodes();
-                       while (it.hasNext()) {
-                               Node remoteNode = it.nextNode();
-                               String uri = remoteNode.getProperty(ARGEO_URI).getString();
-                               try {
-                                       RemoteRepositoryElem remoteRepositoryNode = new RemoteRepositoryElem(remoteNode.getName(),
-                                                       repositoryFactory, uri, this, userSession, jcrKeyring, remoteNode.getPath());
-                                       super.addChild(remoteRepositoryNode);
-                               } catch (Exception e) {
-                                       ErrorFeedback.show("Cannot add remote repository " + remoteNode, e);
-                               }
-                       }
-               }
-       }
-
-       public void registerNewRepository(String alias, Repository repository) {
-               // TODO: implement this
-               // Create a new RepositoryNode Object
-               // add it
-               // super.addChild(new RepositoriesNode(...));
-       }
-
-       /** Returns the {@link RepositoryRegister} wrapped by this object. */
-       public RepositoryRegister getRepositoryRegister() {
-               return repositoryRegister;
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/RepositoryElem.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/RepositoryElem.java
deleted file mode 100644 (file)
index 296c369..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.argeo.cms.ui.jcr.model;
-
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.jcr.JcrUtils;
-
-/**
- * UI Tree component that wraps a JCR {@link Repository}. It also keeps a
- * reference to its parent Tree Ui component; typically the unique
- * {@link RepositoriesElem} object of the current view to enable bi-directionnal
- * browsing in the tree.
- */
-
-public class RepositoryElem extends TreeParent {
-       private String alias;
-       protected Repository repository;
-       private Session defaultSession = null;
-
-       /** Create a new repository with distinct name and alias */
-       public RepositoryElem(String alias, Repository repository, TreeParent parent) {
-               super(alias);
-               this.repository = repository;
-               setParent(parent);
-               this.alias = alias;
-       }
-
-       public void login() {
-               try {
-                       defaultSession = repositoryLogin(CmsConstants.SYS_WORKSPACE);
-                       String[] wkpNames = defaultSession.getWorkspace().getAccessibleWorkspaceNames();
-                       for (String wkpName : wkpNames) {
-                               if (wkpName.equals(defaultSession.getWorkspace().getName()))
-                                       addChild(new WorkspaceElem(this, wkpName, defaultSession));
-                               else
-                                       addChild(new WorkspaceElem(this, wkpName));
-                       }
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot connect to repository " + alias, e);
-               }
-       }
-
-       public synchronized void logout() {
-               for (Object child : getChildren()) {
-                       if (child instanceof WorkspaceElem)
-                               ((WorkspaceElem) child).logout();
-               }
-               clearChildren();
-               JcrUtils.logoutQuietly(defaultSession);
-               defaultSession = null;
-       }
-
-       /**
-        * Actual call to the {@link Repository#login(javax.jcr.Credentials, String)}
-        * method. To be overridden.
-        */
-       protected Session repositoryLogin(String workspaceName) throws RepositoryException {
-               return repository.login(workspaceName);
-       }
-
-       public String[] getAccessibleWorkspaceNames() {
-               try {
-                       return defaultSession.getWorkspace().getAccessibleWorkspaceNames();
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot retrieve workspace names", e);
-               }
-       }
-
-       public void createWorkspace(String workspaceName) {
-               if (!isConnected())
-                       login();
-               try {
-                       defaultSession.getWorkspace().createWorkspace(workspaceName);
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot create workspace", e);
-               }
-       }
-
-       /** returns the {@link Repository} referenced by the current UI Node */
-       public Repository getRepository() {
-               return repository;
-       }
-
-       public String getAlias() {
-               return alias;
-       }
-
-       public Boolean isConnected() {
-               if (defaultSession != null && defaultSession.isLive())
-                       return true;
-               else
-                       return false;
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/SingleJcrNodeElem.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/SingleJcrNodeElem.java
deleted file mode 100644 (file)
index a2584a5..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.argeo.cms.ui.jcr.model;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Workspace;
-
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.argeo.eclipse.ui.EclipseUiException;
-
-/**
- * UI Tree component. Wraps a node of a JCR {@link Workspace}. It also keeps a
- * reference to its parent node that can either be a {@link WorkspaceElem}, a
- * {@link SingleJcrNodeElem} or null if the node is "mounted" as the root of the
- * UI tree.
- */
-public class SingleJcrNodeElem extends TreeParent {
-
-       private final Node node;
-       private String alias = null;
-
-       /** Creates a new UiNode in the UI Tree */
-       public SingleJcrNodeElem(TreeParent parent, Node node, String name) {
-               super(name);
-               setParent(parent);
-               this.node = node;
-       }
-
-       /**
-        * Creates a new UiNode in the UI Tree, keeping a reference to the alias of
-        * the corresponding repository in the current UI environment. It is useful
-        * to be able to mount nodes as roots of the UI tree.
-        */
-       public SingleJcrNodeElem(TreeParent parent, Node node, String name, String alias) {
-               super(name);
-               setParent(parent);
-               this.node = node;
-               this.alias = alias;
-       }
-
-       /** Returns the node wrapped by the current UI object */
-       public Node getNode() {
-               return node;
-       }
-
-       protected String getRepositoryAlias() {
-               return alias;
-       }
-
-       /**
-        * Overrides normal behaviour to initialise children only when first
-        * requested
-        */
-       @Override
-       public synchronized Object[] getChildren() {
-               if (isLoaded()) {
-                       return super.getChildren();
-               } else {
-                       // initialize current object
-                       try {
-                               NodeIterator ni = node.getNodes();
-                               while (ni.hasNext()) {
-                                       Node curNode = ni.nextNode();
-                                       addChild(new SingleJcrNodeElem(this, curNode, curNode.getName()));
-                               }
-                               return super.getChildren();
-                       } catch (RepositoryException re) {
-                               throw new EclipseUiException("Cannot initialize SingleJcrNode children", re);
-                       }
-               }
-       }
-
-       @Override
-       public boolean hasChildren() {
-               try {
-                       if (node.getSession().isLive())
-                               return node.hasNodes();
-                       else
-                               return false;
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Cannot check children node existence", re);
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/WorkspaceElem.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/WorkspaceElem.java
deleted file mode 100644 (file)
index 2d78666..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-package org.argeo.cms.ui.jcr.model;
-
-import javax.jcr.AccessDeniedException;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-// import javax.jcr.Workspace;
-import javax.jcr.Workspace;
-
-import org.argeo.cms.ux.widgets.TreeParent;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.jcr.JcrUtils;
-
-/**
- * UI Tree component. Wraps the root node of a JCR {@link Workspace}. It also
- * keeps a reference to its parent {@link RepositoryElem}, to be able to
- * retrieve alias of the current used repository
- */
-public class WorkspaceElem extends TreeParent {
-       private Session session = null;
-
-       public WorkspaceElem(RepositoryElem parent, String name) {
-               this(parent, name, null);
-       }
-
-       public WorkspaceElem(RepositoryElem parent, String name, Session session) {
-               super(name);
-               this.session = session;
-               setParent(parent);
-       }
-
-       public synchronized Session getSession() {
-               return session;
-       }
-
-       public synchronized Node getRootNode() {
-               try {
-                       if (session != null)
-                               return session.getRootNode();
-                       else
-                               return null;
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot get root node of workspace " + getName(), e);
-               }
-       }
-
-       public synchronized void login() {
-               try {
-                       session = ((RepositoryElem) getParent()).repositoryLogin(getName());
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot connect to repository " + getName(), e);
-               }
-       }
-
-       public Boolean isConnected() {
-               if (session != null && session.isLive())
-                       return true;
-               else
-                       return false;
-       }
-
-       @Override
-       public synchronized void dispose() {
-               logout();
-               super.dispose();
-       }
-
-       /** Logouts the session, does not nothing if there is no live session. */
-       public synchronized void logout() {
-               clearChildren();
-               JcrUtils.logoutQuietly(session);
-               session = null;
-       }
-
-       @Override
-       public synchronized boolean hasChildren() {
-               try {
-                       if (isConnected())
-                               try {
-                                       return session.getRootNode().hasNodes();
-                               } catch (AccessDeniedException e) {
-                                       // current user may not have access to the root node
-                                       return false;
-                               }
-                       else
-                               return false;
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Unexpected error while checking children node existence", re);
-               }
-       }
-
-       /** Override normal behaviour to initialize display of the workspace */
-       @Override
-       public synchronized Object[] getChildren() {
-               if (isLoaded()) {
-                       return super.getChildren();
-               } else {
-                       // initialize current object
-                       try {
-                               Node rootNode;
-                               if (session == null)
-                                       return null;
-                               else
-                                       rootNode = session.getRootNode();
-                               NodeIterator ni = rootNode.getNodes();
-                               while (ni.hasNext()) {
-                                       Node node = ni.nextNode();
-                                       addChild(new SingleJcrNodeElem(this, node, node.getName()));
-                               }
-                               return super.getChildren();
-                       } catch (RepositoryException e) {
-                               throw new EclipseUiException("Cannot initialize WorkspaceNode UI object." + getName(), e);
-                       }
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/package-info.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/model/package-info.java
deleted file mode 100644 (file)
index 8f54744..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Model for SWT/JFace JCR components. */
-package org.argeo.cms.ui.jcr.model;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/package-info.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/jcr/package-info.java
deleted file mode 100644 (file)
index 26ae330..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** SWT/JFace JCR components. */
-package org.argeo.cms.ui.jcr;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/package-info.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/package-info.java
deleted file mode 100644 (file)
index 82fdee7..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** SWT/JFace components for Argeo CMS. */
-package org.argeo.cms.ui;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsLink.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsLink.java
deleted file mode 100644 (file)
index e91f9ba..0000000
+++ /dev/null
@@ -1,282 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsStyle;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.jcr.JcrException;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.service.ResourceManager;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.framework.BundleContext;
-
-/** A link to an internal or external location. */
-public class CmsLink implements CmsUiProvider {
-       private final static CmsLog log = CmsLog.getLog(CmsLink.class);
-       private BundleContext bundleContext;
-
-       private String label;
-       private String style;
-       private String target;
-       private String image;
-       private boolean openNew = false;
-       private MouseListener mouseListener;
-
-       private int horizontalAlignment = SWT.CENTER;
-       private int verticalAlignment = SWT.CENTER;
-
-       private String loggedInLabel = null;
-       private String loggedInTarget = null;
-
-       // internal
-       // private Boolean isUrl = false;
-       private Integer imageWidth, imageHeight;
-
-       public CmsLink() {
-               super();
-       }
-
-       public CmsLink(String label, String target) {
-               this(label, target, (String) null);
-       }
-
-       public CmsLink(String label, String target, CmsStyle style) {
-               this(label, target, style != null ? style.style() : null);
-       }
-
-       public CmsLink(String label, String target, String style) {
-               super();
-               this.label = label;
-               this.target = target;
-               this.style = style;
-               init();
-       }
-
-       public void init() {
-               if (image != null) {
-                       ImageData image = loadImage();
-                       if (imageHeight == null && imageWidth == null) {
-                               imageWidth = image.width;
-                               imageHeight = image.height;
-                       } else if (imageHeight == null) {
-                               imageHeight = (imageWidth * image.height) / image.width;
-                       } else if (imageWidth == null) {
-                               imageWidth = (imageHeight * image.width) / image.height;
-                       }
-               }
-       }
-
-       /** @return {@link Composite} with a single {@link Label} child. */
-       @Override
-       public Control createUi(final Composite parent, Node context) {
-//             if (image != null && (imageWidth == null || imageHeight == null)) {
-//                     throw new CmsException("Image is not properly configured."
-//                                     + " Make sure bundleContext property is set and init() method has been called.");
-//             }
-
-               Composite comp = new Composite(parent, SWT.NONE);
-               comp.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
-               Label link = new Label(comp, SWT.NONE);
-               CmsSwtUtils.markup(link);
-               GridData layoutData = new GridData(horizontalAlignment, verticalAlignment, false, false);
-               if (image != null) {
-                       if (imageHeight != null)
-                               layoutData.heightHint = imageHeight;
-                       if (label == null)
-                               if (imageWidth != null)
-                                       layoutData.widthHint = imageWidth;
-               }
-
-               link.setLayoutData(layoutData);
-               CmsSwtUtils.style(comp, style != null ? style : getDefaultStyle());
-               CmsSwtUtils.style(link, style != null ? style : getDefaultStyle());
-
-               // label
-               StringBuilder labelText = new StringBuilder();
-               if (loggedInTarget != null && isLoggedIn()) {
-                       labelText.append("<a style='color:inherit;text-decoration:inherit;' href=\"");
-                       if (loggedInTarget.equals("")) {
-                               try {
-                                       Node homeNode = CmsJcrUtils.getUserHome(context.getSession());
-                                       String homePath = homeNode.getPath();
-                                       labelText.append("/#" + homePath);
-                               } catch (RepositoryException e) {
-                                       throw new JcrException("Cannot get home path", e);
-                               }
-                       } else {
-                               labelText.append(loggedInTarget);
-                       }
-                       labelText.append("\">");
-               } else if (target != null) {
-                       labelText.append("<a style='color:inherit;text-decoration:inherit;' href='");
-                       labelText.append(target).append("'");
-                       if (openNew) {
-                               labelText.append(" target='_blank'");
-                       }
-                       labelText.append(">");
-               }
-               if (image != null) {
-                       registerImageIfNeeded();
-                       String imageLocation = RWT.getResourceManager().getLocation(image);
-                       labelText.append("<img");
-                       if (imageWidth != null)
-                               labelText.append(" width='").append(imageWidth).append('\'');
-                       if (imageHeight != null)
-                               labelText.append(" height='").append(imageHeight).append('\'');
-                       labelText.append(" src=\"").append(imageLocation).append("\"/>");
-
-               }
-
-               if (loggedInLabel != null && isLoggedIn()) {
-                       labelText.append(' ').append(loggedInLabel);
-               } else if (label != null) {
-                       labelText.append(' ').append(label);
-               }
-
-               if ((loggedInTarget != null && isLoggedIn()) || target != null)
-                       labelText.append("</a>");
-
-               link.setText(labelText.toString());
-
-               if (mouseListener != null)
-                       link.addMouseListener(mouseListener);
-
-               return comp;
-       }
-
-       private void registerImageIfNeeded() {
-               ResourceManager resourceManager = RWT.getResourceManager();
-               if (!resourceManager.isRegistered(image)) {
-                       URL res = getImageUrl();
-                       try (InputStream inputStream = res.openStream()) {
-                               resourceManager.register(image, inputStream);
-                               if (log.isTraceEnabled())
-                                       log.trace("Registered image " + image);
-                       } catch (IOException e) {
-                               throw new RuntimeException("Cannot load image " + image, e);
-                       }
-               }
-       }
-
-       private ImageData loadImage() {
-               URL url = getImageUrl();
-               ImageData result = null;
-               try (InputStream inputStream = url.openStream()) {
-                       result = new ImageData(inputStream);
-                       if (log.isTraceEnabled())
-                               log.trace("Loaded image " + image);
-               } catch (IOException e) {
-                       throw new RuntimeException("Cannot load image " + image, e);
-               }
-               return result;
-       }
-
-       private URL getImageUrl() {
-               URL url;
-               try {
-                       // pure URL
-                       url = new URL(image);
-               } catch (MalformedURLException e1) {
-                       url = bundleContext.getBundle().getResource(image);
-               }
-
-               if (url == null)
-                       throw new IllegalStateException("No image " + image + " available.");
-
-               return url;
-       }
-
-       public void setBundleContext(BundleContext bundleContext) {
-               this.bundleContext = bundleContext;
-       }
-
-       public void setLabel(String label) {
-               this.label = label;
-       }
-
-       public void setStyle(String style) {
-               this.style = style;
-       }
-
-       /** @deprecated Use {@link #setStyle(String)} instead. */
-       @Deprecated
-       public void setCustom(String custom) {
-               this.style = custom;
-       }
-
-       public void setTarget(String target) {
-               this.target = target;
-               // try {
-               // new URL(target);
-               // isUrl = true;
-               // } catch (MalformedURLException e1) {
-               // isUrl = false;
-               // }
-       }
-
-       public void setImage(String image) {
-               this.image = image;
-       }
-
-       public void setLoggedInLabel(String loggedInLabel) {
-               this.loggedInLabel = loggedInLabel;
-       }
-
-       public void setLoggedInTarget(String loggedInTarget) {
-               this.loggedInTarget = loggedInTarget;
-       }
-
-       public void setMouseListener(MouseListener mouseListener) {
-               this.mouseListener = mouseListener;
-       }
-
-       public void setvAlign(String vAlign) {
-               if ("bottom".equals(vAlign)) {
-                       verticalAlignment = SWT.BOTTOM;
-               } else if ("top".equals(vAlign)) {
-                       verticalAlignment = SWT.TOP;
-               } else if ("center".equals(vAlign)) {
-                       verticalAlignment = SWT.CENTER;
-               } else {
-                       throw new IllegalArgumentException(
-                                       "Unsupported vertical alignment " + vAlign + " (must be: top, bottom or center)");
-               }
-       }
-
-       protected boolean isLoggedIn() {
-               return !CurrentUser.isAnonymous();
-       }
-
-       public void setImageWidth(Integer imageWidth) {
-               this.imageWidth = imageWidth;
-       }
-
-       public void setImageHeight(Integer imageHeight) {
-               this.imageHeight = imageHeight;
-       }
-
-       public void setOpenNew(boolean openNew) {
-               this.openNew = openNew;
-       }
-
-       protected String getDefaultStyle() {
-               return SimpleStyle.link.name();
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsPane.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsPane.java
deleted file mode 100644 (file)
index fc0c821..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowLayout;
-import org.eclipse.swt.widgets.Composite;
-
-/** The main pane of a CMS display, with QA and support areas. */
-public class CmsPane {
-
-       private Composite mainArea;
-       private Composite qaArea;
-       private Composite supportArea;
-
-       public CmsPane(Composite parent, int style) {
-               parent.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
-//             qaArea = new Composite(parent, SWT.NONE);
-//             qaArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-//             RowLayout qaLayout = new RowLayout();
-//             qaLayout.spacing = 0;
-//             qaArea.setLayout(qaLayout);
-
-               mainArea = new Composite(parent, SWT.NONE);
-               mainArea.setLayout(new GridLayout());
-               mainArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-
-//             supportArea = new Composite(parent, SWT.NONE);
-//             supportArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-//             RowLayout supportLayout = new RowLayout();
-//             supportLayout.spacing = 0;
-//             supportArea.setLayout(supportLayout);
-       }
-
-       public Composite getMainArea() {
-               return mainArea;
-       }
-
-       public Composite getQaArea() {
-               return qaArea;
-       }
-
-       public Composite getSupportArea() {
-               return supportArea;
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java
deleted file mode 100644 (file)
index 178fbcf..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.servlet.http.HttpServletRequest;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.ux.Cms2DSize;
-import org.argeo.api.cms.ux.CmsView;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiConstants;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.service.ResourceManager;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.layout.RowData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Table;
-
-/** Static utilities for the CMS framework. */
-public class CmsUiUtils {
-       // private final static Log log = LogFactory.getLog(CmsUiUtils.class);
-
-       /*
-        * CMS VIEW
-        */
-
-       /**
-        * The CMS view related to this display, or null if none is available from this
-        * call.
-        * 
-        * @deprecated Use {@link CmsSwtUtils#getCmsView(Composite)} instead.
-        */
-       @Deprecated
-       public static CmsView getCmsView() {
-//             return UiContext.getData(CmsView.class.getName());
-               return CmsSwtUtils.getCmsView(Display.getCurrent().getActiveShell());
-       }
-
-       public static StringBuilder getServerBaseUrl(HttpServletRequest request) {
-               try {
-                       URL url = new URL(request.getRequestURL().toString());
-                       StringBuilder buf = new StringBuilder();
-                       buf.append(url.getProtocol()).append("://").append(url.getHost());
-                       if (url.getPort() != -1)
-                               buf.append(':').append(url.getPort());
-                       return buf;
-               } catch (MalformedURLException e) {
-                       throw new IllegalArgumentException("Cannot extract server base URL from " + request.getRequestURL(), e);
-               }
-       }
-
-       //
-       public static String getDataUrl(Node node, HttpServletRequest request) {
-               try {
-                       StringBuilder buf = getServerBaseUrl(request);
-                       buf.append(getDataPath(node));
-                       return new URL(buf.toString()).toString();
-               } catch (MalformedURLException e) {
-                       throw new IllegalArgumentException("Cannot build data URL for " + node, e);
-               }
-       }
-
-       /** A path in the node repository */
-       public static String getDataPath(Node node) {
-               return getDataPath(CmsConstants.EGO_REPOSITORY, node);
-       }
-
-       public static String getDataPath(String cn, Node node) {
-               return CmsJcrUtils.getDataPath(cn, node);
-       }
-
-       /** Clean reserved URL characters for use in HTTP links. */
-       public static String getDataPathForUrl(Node node) {
-               return CmsSwtUtils.cleanPathForUrl(getDataPath(node));
-       }
-
-       /** @deprecated Use rowData16px() instead. GridData should not be reused. */
-       @Deprecated
-       public static RowData ROW_DATA_16px = new RowData(16, 16);
-
-       
-
-       /*
-        * FORM LAYOUT
-        */
-
-       
-
-       @Deprecated
-       public static void setItemHeight(Table table, int height) {
-               table.setData(CmsUiConstants.ITEM_HEIGHT, height);
-       }
-
-       //
-       // JCR
-       //
-       public static Node getOrAddEmptyFile(Node parent, Enum<?> child) throws RepositoryException {
-               if (has(parent, child))
-                       return child(parent, child);
-               return JcrUtils.copyBytesAsFile(parent, child.name(), new byte[0]);
-       }
-
-       public static Node child(Node parent, Enum<?> en) throws RepositoryException {
-               return parent.getNode(en.name());
-       }
-
-       public static Boolean has(Node parent, Enum<?> en) throws RepositoryException {
-               return parent.hasNode(en.name());
-       }
-
-       public static Node getOrAdd(Node parent, Enum<?> en) throws RepositoryException {
-               return getOrAdd(parent, en, null);
-       }
-
-       public static Node getOrAdd(Node parent, Enum<?> en, String primaryType) throws RepositoryException {
-               if (has(parent, en))
-                       return child(parent, en);
-               else if (primaryType == null)
-                       return parent.addNode(en.name());
-               else
-                       return parent.addNode(en.name(), primaryType);
-       }
-
-       // IMAGES
-
-       public static String img(Node fileNode, String width, String height) {
-               return img(null, fileNode, width, height);
-       }
-
-       public static String img(String serverBase, Node fileNode, String width, String height) {
-//             String src = (serverBase != null ? serverBase : "") + NodeUtils.getDataPath(fileNode);
-               String src;
-               src = (serverBase != null ? serverBase : "") + getDataPathForUrl(fileNode);
-               return imgBuilder(src, width, height).append("/>").toString();
-       }
-
-       public static String img(String src, String width, String height) {
-               return imgBuilder(src, width, height).append("/>").toString();
-       }
-
-       public static String img(String src, Cms2DSize size) {
-               return img(src, Integer.toString(size.getWidth()), Integer.toString(size.getHeight()));
-       }
-
-       public static StringBuilder imgBuilder(String src, String width, String height) {
-               return new StringBuilder(64).append("<img width='").append(width).append("' height='").append(height)
-                               .append("' src='").append(src).append("'");
-       }
-
-       public static String noImg(Cms2DSize size) {
-               ResourceManager rm = RWT.getResourceManager();
-               return CmsUiUtils.img(rm.getLocation(CmsUiConstants.NO_IMAGE), size);
-       }
-
-       public static String noImg() {
-               return noImg(CmsUiConstants.NO_IMAGE_SIZE);
-       }
-
-       public static Image noImage(Cms2DSize size) {
-               ResourceManager rm = RWT.getResourceManager();
-               InputStream in = null;
-               try {
-                       in = rm.getRegisteredContent(CmsUiConstants.NO_IMAGE);
-                       ImageData id = new ImageData(in);
-                       ImageData scaled = id.scaledTo(size.getWidth(), size.getHeight());
-                       Image image = new Image(Display.getCurrent(), scaled);
-                       return image;
-               } finally {
-                       try {
-                               in.close();
-                       } catch (IOException e) {
-                               // silent
-                       }
-               }
-       }
-
-       /** Lorem ipsum text to be used during development. */
-       public final static String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
-                       + " Etiam eleifend hendrerit sem, ac ultricies massa ornare ac."
-                       + " Cras aliquam sodales risus, vitae varius lacus molestie quis."
-                       + " Vivamus consequat, leo id lacinia volutpat, eros diam efficitur urna, finibus interdum risus turpis at nisi."
-                       + " Curabitur vulputate nulla quis scelerisque fringilla. Integer consectetur turpis id lobortis accumsan."
-                       + " Pellentesque commodo turpis ac diam ultricies dignissim."
-                       + " Curabitur sit amet dolor volutpat lacus aliquam ornare quis sed velit."
-                       + " Integer varius quis est et tristique."
-                       + " Suspendisse pharetra porttitor purus, eget condimentum magna."
-                       + " Duis vitae turpis eros. Sed tincidunt lacinia rutrum."
-                       + " Aliquam velit velit, rutrum ut augue sed, condimentum lacinia augue.";
-
-       /** Singleton. */
-       private CmsUiUtils() {
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/DefaultImageManager.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/DefaultImageManager.java
deleted file mode 100644 (file)
index 1ec2622..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import static javax.jcr.Node.JCR_CONTENT;
-import static javax.jcr.Property.JCR_DATA;
-import static javax.jcr.nodetype.NodeType.NT_FILE;
-import static javax.jcr.nodetype.NodeType.NT_RESOURCE;
-import static org.argeo.cms.ui.CmsUiConstants.NO_IMAGE_SIZE;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-
-import javax.jcr.Binary;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.Cms2DSize;
-import org.argeo.api.cms.ux.CmsImageManager;
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.service.ResourceManager;
-import org.eclipse.rap.rwt.widgets.FileUpload;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-
-/** Manages only public images so far. */
-public class DefaultImageManager implements CmsImageManager<Control, Node> {
-       private final static CmsLog log = CmsLog.getLog(DefaultImageManager.class);
-//     private MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap();
-
-       public Boolean load(Node node, Control control, Cms2DSize preferredSize) {
-               Cms2DSize imageSize = getImageSize(node);
-               Cms2DSize size;
-               String imgTag = null;
-               if (preferredSize == null || imageSize.getWidth() == 0 || imageSize.getHeight() == 0
-                               || (preferredSize.getWidth() == 0 && preferredSize.getHeight() == 0)) {
-                       if (imageSize.getWidth() != 0 && imageSize.getHeight() != 0) {
-                               // actual image size if completely known
-                               size = imageSize;
-                       } else {
-                               // no image if not completely known
-                               size = resizeTo(NO_IMAGE_SIZE, preferredSize != null ? preferredSize : imageSize);
-                               imgTag = CmsUiUtils.noImg(size);
-                       }
-
-               } else if (preferredSize.getWidth() != 0 && preferredSize.getHeight() != 0) {
-                       // given size if completely provided
-                       size = preferredSize;
-               } else {
-                       // at this stage :
-                       // image is completely known
-                       assert imageSize.getWidth() != 0 && imageSize.getHeight() != 0;
-                       // one and only one of the dimension as been specified
-                       assert preferredSize.getWidth() == 0 || preferredSize.getHeight() == 0;
-                       size = resizeTo(imageSize, preferredSize);
-               }
-
-               boolean loaded = false;
-               if (control == null)
-                       return loaded;
-
-               if (control instanceof Label) {
-                       if (imgTag == null) {
-                               // IMAGE RETRIEVED HERE
-                               imgTag = getImageTag(node, size);
-                               //
-                               if (imgTag == null)
-                                       imgTag = CmsUiUtils.noImg(size);
-                               else
-                                       loaded = true;
-                       }
-
-                       Label lbl = (Label) control;
-                       lbl.setText(imgTag);
-                       // lbl.setSize(size);
-               } else if (control instanceof FileUpload) {
-                       FileUpload lbl = (FileUpload) control;
-                       lbl.setImage(CmsUiUtils.noImage(size));
-                       lbl.setSize(new Point(size.getWidth(), size.getHeight()));
-                       return loaded;
-               } else
-                       loaded = false;
-
-               return loaded;
-       }
-
-       private Cms2DSize resizeTo(Cms2DSize orig, Cms2DSize constraints) {
-               if (constraints.getWidth() != 0 && constraints.getHeight() != 0) {
-                       return constraints;
-               } else if (constraints.getWidth() == 0 && constraints.getHeight() == 0) {
-                       return orig;
-               } else if (constraints.getHeight() == 0) {// force width
-                       return new Cms2DSize(constraints.getWidth(),
-                                       scale(orig.getHeight(), orig.getWidth(), constraints.getWidth()));
-               } else if (constraints.getWidth() == 0) {// force height
-                       return new Cms2DSize(scale(orig.getWidth(), orig.getHeight(), constraints.getHeight()),
-                                       constraints.getHeight());
-               }
-               throw new IllegalArgumentException("Cannot resize " + orig + " to " + constraints);
-       }
-
-       private int scale(int origDimension, int otherDimension, int otherConstraint) {
-               return Math.round(origDimension * divide(otherConstraint, otherDimension));
-       }
-
-       private float divide(int a, int b) {
-               return ((float) a) / ((float) b);
-       }
-
-       public Cms2DSize getImageSize(Node node) {
-               // TODO optimise
-               Image image = getSwtImage(node);
-               return new Cms2DSize(image.getBounds().width, image.getBounds().height);
-       }
-
-       /** @return null if not available */
-       @Override
-       public String getImageTag(Node node) {
-               return getImageTag(node, getImageSize(node));
-       }
-
-       private String getImageTag(Node node, Cms2DSize size) {
-               StringBuilder buf = getImageTagBuilder(node, size);
-               if (buf == null)
-                       return null;
-               return buf.append("/>").toString();
-       }
-
-       /** @return null if not available */
-       @Override
-       public StringBuilder getImageTagBuilder(Node node, Cms2DSize size) {
-               return getImageTagBuilder(node, Integer.toString(size.getWidth()), Integer.toString(size.getHeight()));
-       }
-
-       /** @return null if not available */
-       private StringBuilder getImageTagBuilder(Node node, String width, String height) {
-               String url = getImageUrl(node);
-               if (url == null)
-                       return null;
-               return CmsUiUtils.imgBuilder(url, width, height);
-       }
-
-       /** @return null if not available */
-       @Override
-       public String getImageUrl(Node node) {
-               return CmsUiUtils.getDataPathForUrl(node);
-       }
-
-       protected String getResourceName(Node node) {
-               try {
-                       String workspace = node.getSession().getWorkspace().getName();
-                       if (node.hasNode(JCR_CONTENT))
-                               return workspace + '_' + node.getNode(JCR_CONTENT).getIdentifier();
-                       else
-                               return workspace + '_' + node.getIdentifier();
-               } catch (RepositoryException e) {
-                       throw new JcrException(e);
-               }
-       }
-
-       public Binary getImageBinary(Node node) {
-               try {
-                       if (node.isNodeType(NT_FILE)) {
-                               return node.getNode(JCR_CONTENT).getProperty(JCR_DATA).getBinary();
-                       } else {
-                               return null;
-                       }
-               } catch (RepositoryException e) {
-                       throw new JcrException(e);
-               }
-       }
-
-       public Image getSwtImage(Node node) {
-               InputStream inputStream = null;
-               Binary binary = getImageBinary(node);
-               if (binary == null)
-                       return null;
-               try {
-                       inputStream = binary.getStream();
-                       return new Image(Display.getCurrent(), inputStream);
-               } catch (RepositoryException e) {
-                       throw new JcrException(e);
-               } finally {
-                       IOUtils.closeQuietly(inputStream);
-                       JcrUtils.closeQuietly(binary);
-               }
-       }
-
-       @Override
-       public String uploadImage(Node context, Node parentNode, String fileName, InputStream in, String contentType) {
-               InputStream inputStream = null;
-               try {
-                       String previousResourceName = null;
-                       if (parentNode.hasNode(fileName)) {
-                               Node node = parentNode.getNode(fileName);
-                               previousResourceName = getResourceName(node);
-                               if (node.hasNode(JCR_CONTENT)) {
-                                       node.getNode(JCR_CONTENT).remove();
-                                       node.addNode(JCR_CONTENT, NT_RESOURCE);
-                               }
-                       }
-
-                       byte[] arr = IOUtils.toByteArray(in);
-                       Node fileNode = JcrUtils.copyBytesAsFile(parentNode, fileName, arr);
-                       inputStream = new ByteArrayInputStream(arr);
-                       ImageData id = new ImageData(inputStream);
-                       processNewImageFile(context, fileNode, id);
-
-                       String mime = contentType != null ? contentType : Files.probeContentType(Paths.get(fileName));
-                       if (mime != null) {
-                               fileNode.getNode(JCR_CONTENT).setProperty(Property.JCR_MIMETYPE, mime);
-                       }
-                       fileNode.getSession().save();
-
-                       // reset resource manager
-                       ResourceManager resourceManager = RWT.getResourceManager();
-                       if (previousResourceName != null && resourceManager.isRegistered(previousResourceName)) {
-                               resourceManager.unregister(previousResourceName);
-                               if (log.isDebugEnabled())
-                                       log.debug("Unregistered image " + previousResourceName);
-                       }
-                       return CmsUiUtils.getDataPath(fileNode);
-               } catch (IOException e) {
-                       throw new RuntimeException("Cannot upload image " + fileName + " in " + parentNode, e);
-               } catch (RepositoryException e) {
-                       throw new JcrException(e);
-               } finally {
-                       IOUtils.closeQuietly(inputStream);
-               }
-       }
-
-       /** Does nothing by default. */
-       protected void processNewImageFile(Node context, Node fileNode, ImageData id)
-                       throws RepositoryException, IOException {
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/MenuLink.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/MenuLink.java
deleted file mode 100644 (file)
index 284d2bd..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import org.argeo.cms.swt.CmsStyles;
-
-/**
- * Convenience class setting the custom style {@link CmsStyles#CMS_MENU_LINK} on
- * a {@link CmsLink} when simple menus are used.
- */
-public class MenuLink extends CmsLink {
-       public MenuLink() {
-               setCustom(CmsStyles.CMS_MENU_LINK);
-       }
-
-       public MenuLink(String label, String target, String custom) {
-               super(label, target, custom);
-       }
-
-       public MenuLink(String label, String target) {
-               super(label, target, CmsStyles.CMS_MENU_LINK);
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleCmsHeader.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleCmsHeader.java
deleted file mode 100644 (file)
index ab6a29f..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.swt.CmsStyles;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** A header in three parts */
-public class SimpleCmsHeader implements CmsUiProvider {
-       private List<CmsUiProvider> lead = new ArrayList<CmsUiProvider>();
-       private List<CmsUiProvider> center = new ArrayList<CmsUiProvider>();
-       private List<CmsUiProvider> end = new ArrayList<CmsUiProvider>();
-
-       private Boolean subPartsSameWidth = false;
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               Composite header = new Composite(parent, SWT.NONE);
-               header.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_HEADER);
-               header.setBackgroundMode(SWT.INHERIT_DEFAULT);
-               header.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(3, false)));
-
-               configurePart(context, header, lead);
-               configurePart(context, header, center);
-               configurePart(context, header, end);
-               return header;
-       }
-
-       protected void configurePart(Node context, Composite parent, List<CmsUiProvider> partProviders)
-                       throws RepositoryException {
-               final int style;
-               final String custom;
-               if (lead == partProviders) {
-                       style = SWT.LEAD;
-                       custom = CmsStyles.CMS_HEADER_LEAD;
-               } else if (center == partProviders) {
-                       style = SWT.CENTER;
-                       custom = CmsStyles.CMS_HEADER_CENTER;
-               } else if (end == partProviders) {
-                       style = SWT.END;
-                       custom = CmsStyles.CMS_HEADER_END;
-               } else {
-                       throw new CmsException("Unsupported part providers " + partProviders);
-               }
-
-               Composite part = new Composite(parent, SWT.NONE);
-               part.setData(RWT.CUSTOM_VARIANT, custom);
-               GridData gridData = new GridData(style, SWT.FILL, true, true);
-               part.setLayoutData(gridData);
-               part.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(partProviders.size(), subPartsSameWidth)));
-               for (CmsUiProvider uiProvider : partProviders) {
-                       Control subPart = uiProvider.createUi(part, context);
-                       subPart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               }
-       }
-
-       public void setLead(List<CmsUiProvider> lead) {
-               this.lead = lead;
-       }
-
-       public void setCenter(List<CmsUiProvider> center) {
-               this.center = center;
-       }
-
-       public void setEnd(List<CmsUiProvider> end) {
-               this.end = end;
-       }
-
-       public void setSubPartsSameWidth(Boolean subPartsSameWidth) {
-               this.subPartsSameWidth = subPartsSameWidth;
-       }
-
-       public List<CmsUiProvider> getLead() {
-               return lead;
-       }
-
-       public List<CmsUiProvider> getCenter() {
-               return center;
-       }
-
-       public List<CmsUiProvider> getEnd() {
-               return end;
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleDynamicPages.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleDynamicPages.java
deleted file mode 100644 (file)
index c61a2fc..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-public class SimpleDynamicPages implements CmsUiProvider {
-
-       @Override
-       public Control createUi(Composite parent, Node context)
-                       throws RepositoryException {
-               if (context == null)
-                       throw new CmsException("Context cannot be null");
-               parent.setLayout(new GridLayout(2, false));
-
-               // parent
-               if (!context.getPath().equals("/")) {
-                       new CmsLink("..", context.getParent().getPath()).createUi(parent,
-                                       context);
-                       new Label(parent, SWT.NONE).setText(context.getParent()
-                                       .getPrimaryNodeType().getName());
-               }
-
-               // context
-               Label contextL = new Label(parent, SWT.NONE);
-               contextL.setData(RWT.MARKUP_ENABLED, true);
-               contextL.setText("<b>" + context.getName() + "</b>");
-               new Label(parent, SWT.NONE).setText(context.getPrimaryNodeType()
-                               .getName());
-
-               // children
-               // Label childrenL = new Label(parent, SWT.NONE);
-               // childrenL.setData(RWT.MARKUP_ENABLED, true);
-               // childrenL.setText("<i>Children:</i>");
-               // childrenL.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false,
-               // false, 2, 1));
-
-               for (NodeIterator nIt = context.getNodes(); nIt.hasNext();) {
-                       Node child = nIt.nextNode();
-                       new CmsLink(child.getName(), child.getPath()).createUi(parent,
-                                       context);
-
-                       new Label(parent, SWT.NONE).setText(child.getPrimaryNodeType()
-                                       .getName());
-               }
-
-               // properties
-               // Label propsL = new Label(parent, SWT.NONE);
-               // propsL.setData(RWT.MARKUP_ENABLED, true);
-               // propsL.setText("<i>Properties:</i>");
-               // propsL.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false,
-               // 2, 1));
-               for (PropertyIterator pIt = context.getProperties(); pIt.hasNext();) {
-                       Property property = pIt.nextProperty();
-
-                       Label label = new Label(parent, SWT.NONE);
-                       label.setText(property.getName());
-                       label.setToolTipText(JcrUtils
-                                       .getPropertyDefinitionAsString(property));
-
-                       new Label(parent, SWT.NONE).setText(getPropAsString(property));
-               }
-
-               return null;
-       }
-
-       private String getPropAsString(Property property)
-                       throws RepositoryException {
-               String result = "";
-               DateFormat timeFormatter = new SimpleDateFormat("");
-               if (property.isMultiple()) {
-                       result = getMultiAsString(property, ", ");
-               } else {
-                       Value value = property.getValue();
-                       if (value.getType() == PropertyType.BINARY)
-                               result = "<binary>";
-                       else if (value.getType() == PropertyType.DATE)
-                               result = timeFormatter.format(value.getDate().getTime());
-                       else
-                               result = value.getString();
-               }
-               return result;
-       }
-
-       private String getMultiAsString(Property property, String separator)
-                       throws RepositoryException {
-               if (separator == null)
-                       separator = "; ";
-               Value[] values = property.getValues();
-               StringBuilder builder = new StringBuilder();
-               for (Value val : values) {
-                       String currStr = val.getString();
-                       if (!"".equals(currStr.trim()))
-                               builder.append(currStr).append(separator);
-               }
-               if (builder.lastIndexOf(separator) >= 0)
-                       return builder.substring(0, builder.length() - separator.length());
-               else
-                       return builder.toString();
-       }
-}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleImageManager.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleImageManager.java
deleted file mode 100644 (file)
index ac09b2a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.argeo.cms.ui.util;
-
-public class SimpleImageManager extends DefaultImageManager {
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStaticPage.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStaticPage.java
deleted file mode 100644 (file)
index 63e504b..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsStyles;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-public class SimpleStaticPage implements CmsUiProvider {
-       private String text;
-
-       @Override
-       public Control createUi(Composite parent, Node context)
-                       throws RepositoryException {
-               Label textC = new Label(parent,  SWT.WRAP);
-               textC.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_STATIC_TEXT);
-               textC.setData(RWT.MARKUP_ENABLED, Boolean.TRUE);
-               textC.setText(text);
-               
-               return textC;
-       }
-
-       public void setText(String text) {
-               this.text = text;
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStyle.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SimpleStyle.java
deleted file mode 100644 (file)
index b5fca26..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import org.argeo.api.cms.ux.CmsStyle;
-
-/** Simple styles used by the CMS UI utilities. */
-public enum SimpleStyle implements CmsStyle {
-       link;
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/StyleSheetResourceLoader.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/StyleSheetResourceLoader.java
deleted file mode 100644 (file)
index 1e17dc9..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.cms.swt.CmsException;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.osgi.framework.Bundle;
-
-/** {@link ResourceLoader} caching stylesheets. */
-public class StyleSheetResourceLoader implements ResourceLoader {
-       private Bundle themeBundle;
-       private Map<String, StyleSheet> stylesheets = new LinkedHashMap<String, StyleSheet>();
-
-       public StyleSheetResourceLoader(Bundle themeBundle) {
-               this.themeBundle = themeBundle;
-       }
-
-       @Override
-       public InputStream getResourceAsStream(String resourceName) throws IOException {
-               if (!stylesheets.containsKey(resourceName)) {
-                       // TODO deal with other bundles
-                       // Bundle bundle = bundleContext.getBundle();
-                       // String location =
-                       // bundle.getLocation().substring("initial@reference:".length());
-                       // if (location.startsWith("file:")) {
-                       // Path path = null;
-                       // try {
-                       // path = Paths.get(new URI(location));
-                       // } catch (URISyntaxException e) {
-                       // e.printStackTrace();
-                       // }
-                       // if (path != null) {
-                       // Path resourcePath = path.resolve(resourceName);
-                       // if (Files.exists(resourcePath))
-                       // return Files.newInputStream(resourcePath);
-                       // }
-                       // }
-
-                       URL res = themeBundle.getEntry(resourceName);
-                       if (res == null)
-                               throw new CmsException(
-                                               "Entry " + resourceName + " not found in bundle " + themeBundle.getSymbolicName());
-                       ByteArrayOutputStream out = new ByteArrayOutputStream();
-                       IOUtils.copy(res.openStream(), out);
-                       stylesheets.put(resourceName, new StyleSheet(out.toByteArray()));
-               }
-               return new ByteArrayInputStream(stylesheets.get(resourceName).getData());
-               // return res.openStream();
-       }
-
-       private class StyleSheet {
-               private byte[] data;
-
-               public StyleSheet(byte[] data) {
-                       super();
-                       this.data = data;
-               }
-
-               public byte[] getData() {
-                       return data;
-               }
-
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SystemNotifications.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/SystemNotifications.java
deleted file mode 100644 (file)
index 5a00781..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.swt.CmsStyles;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.events.ShellAdapter;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-
-/** Shell displaying system notifications such as exceptions */
-public class SystemNotifications extends Shell implements CmsStyles,
-               MouseListener {
-       private static final long serialVersionUID = -8129377525216022683L;
-
-       private Control source;
-
-       public SystemNotifications(Control source) {
-               super(source.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
-               setData(RWT.CUSTOM_VARIANT, CMS_USER_MENU);
-
-               this.source = source;
-
-               // TODO UI
-               // setLocation(source.toDisplay(source.getSize().x - getSize().x,
-               // source.getSize().y));
-               setLayout(new GridLayout());
-               addMouseListener(this);
-
-               addShellListener(new ShellAdapter() {
-                       private static final long serialVersionUID = 5178980294808435833L;
-
-                       @Override
-                       public void shellDeactivated(ShellEvent e) {
-                               close();
-                               dispose();
-                       }
-               });
-
-       }
-
-       public void notifyException(Throwable exception) {
-               Composite pane = this;
-
-               Label lbl = new Label(pane, SWT.NONE);
-               lbl.setText(exception.getLocalizedMessage()
-                               + (exception instanceof CmsException ? "" : "("
-                                               + exception.getClass().getName() + ")") + "\n");
-               lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-               lbl.addMouseListener(this);
-               if (exception.getCause() != null)
-                       appendCause(pane, exception.getCause());
-
-               StringBuilder mailToUrl = new StringBuilder("mailto:?");
-               try {
-                       mailToUrl.append("subject=").append(
-                                       URLEncoder.encode(
-                                                       "Exception "
-                                                                       + new SimpleDateFormat("yyyy-MM-dd hh:mm")
-                                                                                       .format(new Date()), "UTF-8")
-                                                       .replace("+", "%20"));
-
-                       StringWriter sw = new StringWriter();
-                       exception.printStackTrace(new PrintWriter(sw));
-                       IOUtils.closeQuietly(sw);
-
-                       // see
-                       // http://stackoverflow.com/questions/4737841/urlencoder-not-able-to-translate-space-character
-                       String encoded = URLEncoder.encode(sw.toString(), "UTF-8").replace(
-                                       "+", "%20");
-                       mailToUrl.append("&amp;body=").append(encoded);
-               } catch (UnsupportedEncodingException e) {
-                       mailToUrl.append("&amp;body=").append("Could not encode: ")
-                                       .append(e.getMessage());
-               }
-               Label mailTo = new Label(pane, SWT.NONE);
-               CmsSwtUtils.markup(mailTo);
-               mailTo.setText("<a href=\"" + mailToUrl + "\">Send details</a>");
-               mailTo.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
-
-               pack();
-               layout();
-
-               setLocation(source.toDisplay(source.getSize().x - getSize().x,
-                               source.getSize().y - getSize().y));
-               open();
-       }
-
-       private void appendCause(Composite parent, Throwable e) {
-               Label lbl = new Label(parent, SWT.NONE);
-               lbl.setText(" caused by: " + e.getLocalizedMessage() + " ("
-                               + e.getClass().getName() + ")" + "\n");
-               lbl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-               lbl.addMouseListener(this);
-               if (e.getCause() != null)
-                       appendCause(parent, e.getCause());
-       }
-
-       @Override
-       public void mouseDoubleClick(MouseEvent e) {
-       }
-
-       @Override
-       public void mouseDown(MouseEvent e) {
-               close();
-               dispose();
-       }
-
-       @Override
-       public void mouseUp(MouseEvent e) {
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenu.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenu.java
deleted file mode 100644 (file)
index 09aeff6..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.swt.auth.CmsLoginShell;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ShellAdapter;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-
-/** The site-related user menu */
-public class UserMenu extends CmsLoginShell {
-       private final Control source;
-       private final Node context;
-
-       public UserMenu(Control source, Node context) {
-               // FIXME pass CMS context
-               super(CmsUiUtils.getCmsView(), null);
-               this.context = context;
-               createUi();
-               if (source == null)
-                       throw new CmsException("Source control cannot be null.");
-               this.source = source;
-               open();
-       }
-
-       @Override
-       protected Shell createShell() {
-               return new Shell(Display.getCurrent(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
-       }
-
-       @Override
-       public void open() {
-               Shell shell = getShell();
-               shell.pack();
-               shell.layout();
-               shell.setLocation(source.toDisplay(source.getSize().x - shell.getSize().x, source.getSize().y));
-               shell.addShellListener(new ShellAdapter() {
-                       private static final long serialVersionUID = 5178980294808435833L;
-
-                       @Override
-                       public void shellDeactivated(ShellEvent e) {
-                               closeShell();
-                       }
-               });
-               super.open();
-       }
-
-       protected Node getContext() {
-               return context;
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenuLink.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/UserMenuLink.java
deleted file mode 100644 (file)
index 317a7b5..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import javax.jcr.Node;
-
-import org.argeo.cms.CmsMsg;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.swt.CmsStyles;
-import org.argeo.cms.swt.auth.CmsLoginShell;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-
-/** Open the user menu when clicked */
-public class UserMenuLink extends MenuLink {
-
-       public UserMenuLink() {
-               setCustom(CmsStyles.CMS_USER_MENU_LINK);
-       }
-
-       @Override
-       public Control createUi(Composite parent, Node context) {
-               if (CurrentUser.isAnonymous())
-                       setLabel(CmsMsg.login.lead());
-               else {
-                       setLabel(CurrentUser.getDisplayName());
-               }
-               Label link = (Label) ((Composite) super.createUi(parent, context)).getChildren()[0];
-               link.addMouseListener(new UserMenuLinkController(context));
-               return link.getParent();
-       }
-
-       protected CmsLoginShell createUserMenu(Control source, Node context) {
-               return new UserMenu(source.getParent(), context);
-       }
-
-       private class UserMenuLinkController implements MouseListener, DisposeListener {
-               private static final long serialVersionUID = 3634864186295639792L;
-
-               private CmsLoginShell userMenu = null;
-               private long lastDisposeTS = 0l;
-
-               private final Node context;
-
-               public UserMenuLinkController(Node context) {
-                       this.context = context;
-               }
-
-               //
-               // MOUSE LISTENER
-               //
-               @Override
-               public void mouseDown(MouseEvent e) {
-                       if (e.button == 1) {
-                               Control source = (Control) e.getSource();
-                               if (userMenu == null) {
-                                       long durationSinceLastDispose = System.currentTimeMillis() - lastDisposeTS;
-                                       // avoid to reopen the menu, if one has clicked gain
-                                       if (durationSinceLastDispose > 200) {
-                                               userMenu = createUserMenu(source, context);
-                                               userMenu.getShell().addDisposeListener(this);
-                                       }
-                               }
-                       }
-               }
-
-               @Override
-               public void mouseDoubleClick(MouseEvent e) {
-               }
-
-               @Override
-               public void mouseUp(MouseEvent e) {
-               }
-
-               @Override
-               public void widgetDisposed(DisposeEvent event) {
-                       userMenu = null;
-                       lastDisposeTS = System.currentTimeMillis();
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/VerticalMenu.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/VerticalMenu.java
deleted file mode 100644 (file)
index 7f846c9..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.argeo.cms.ui.util;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.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;
-
-public class VerticalMenu implements CmsUiProvider {
-       private List<CmsUiProvider> items = new ArrayList<CmsUiProvider>();
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               Composite part = new Composite(parent, SWT.NONE);
-               part.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
-//             part.setData(RWT.CUSTOM_VARIANT, custom);
-               part.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               for (CmsUiProvider uiProvider : items) {
-                       Control subPart = uiProvider.createUi(part, context);
-                       subPart.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
-               }
-               return part;
-       }
-
-       public void add(CmsUiProvider uiProvider) {
-               items.add(uiProvider);
-       }
-
-       public List<CmsUiProvider> getItems() {
-               return items;
-       }
-
-       public void setItems(List<CmsUiProvider> items) {
-               this.items = items;
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/package-info.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/package-info.java
deleted file mode 100644 (file)
index 566df88..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Argeo CMS UI utilities. */
-package org.argeo.cms.ui.util;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/AbstractPageViewer.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/AbstractPageViewer.java
deleted file mode 100644 (file)
index e23846e..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-package org.argeo.cms.ui.viewers;
-
-import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.Observable;
-import java.util.Observer;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.security.auth.Subject;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsEditable;
-import org.argeo.cms.swt.SwtEditablePart;
-import org.argeo.cms.swt.widgets.ScrolledPage;
-import org.argeo.jcr.JcrException;
-import org.eclipse.jface.viewers.ContentViewer;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.StructuredSelection;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Widget;
-import org.xml.sax.SAXParseException;
-
-/** Base class for viewers related to a page */
-public abstract class AbstractPageViewer extends ContentViewer implements Observer {
-       private static final long serialVersionUID = 5438688173410341485L;
-
-       private final static CmsLog log = CmsLog.getLog(AbstractPageViewer.class);
-
-       private final boolean readOnly;
-       /** The basis for the layouts, typically a ScrolledPage. */
-       private final Composite page;
-       private final CmsEditable cmsEditable;
-
-       private MouseListener mouseListener;
-       private FocusListener focusListener;
-
-       private SwtEditablePart edited;
-       private ISelection selection = StructuredSelection.EMPTY;
-
-       private AccessControlContext accessControlContext;
-
-       protected AbstractPageViewer(Section parent, int style, CmsEditable cmsEditable) {
-               // read only at UI level
-               readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
-
-               this.cmsEditable = cmsEditable == null ? CmsEditable.NON_EDITABLE : cmsEditable;
-               if (this.cmsEditable instanceof Observable)
-                       ((Observable) this.cmsEditable).addObserver(this);
-
-               if (cmsEditable.canEdit()) {
-                       mouseListener = createMouseListener();
-                       focusListener = createFocusListener();
-               }
-               page = findPage(parent);
-               accessControlContext = AccessController.getContext();
-       }
-
-       /**
-        * Can be called to simplify the called to isModelInitialized() and initModel()
-        */
-       protected void initModelIfNeeded(Node node) {
-               try {
-                       if (!isModelInitialized(node))
-                               if (getCmsEditable().canEdit()) {
-                                       initModel(node);
-                                       node.getSession().save();
-                               }
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot initialize model", e);
-               }
-       }
-
-       /** Called if user can edit and model is not initialized */
-       protected Boolean isModelInitialized(Node node) throws RepositoryException {
-               return true;
-       }
-
-       /** Called if user can edit and model is not initialized */
-       protected void initModel(Node node) throws RepositoryException {
-       }
-
-       /** Create (retrieve) the MouseListener to use. */
-       protected MouseListener createMouseListener() {
-               return new MouseAdapter() {
-                       private static final long serialVersionUID = 1L;
-               };
-       }
-
-       /** Create (retrieve) the FocusListener to use. */
-       protected FocusListener createFocusListener() {
-               return new FocusListener() {
-                       private static final long serialVersionUID = 1L;
-
-                       @Override
-                       public void focusLost(FocusEvent event) {
-                       }
-
-                       @Override
-                       public void focusGained(FocusEvent event) {
-                       }
-               };
-       }
-
-       protected Composite findPage(Composite composite) {
-               if (composite instanceof ScrolledPage) {
-                       return (ScrolledPage) composite;
-               } else {
-                       if (composite.getParent() == null)
-                               return composite;
-                       return findPage(composite.getParent());
-               }
-       }
-
-       public void layoutPage() {
-               if (page != null)
-                       page.layout(true, true);
-       }
-
-       protected void showControl(Control control) {
-               if (page != null && (page instanceof ScrolledPage))
-                       ((ScrolledPage) page).showControl(control);
-       }
-
-       @Override
-       public void update(Observable o, Object arg) {
-               if (o == cmsEditable)
-                       editingStateChanged(cmsEditable);
-       }
-
-       /** To be overridden in order to provide the actual refresh */
-       protected void refresh(Control control) throws RepositoryException {
-       }
-
-       /** To be overridden.Save the edited part. */
-       protected void save(SwtEditablePart part) throws RepositoryException {
-       }
-
-       /** Prepare the edited part */
-       protected void prepare(SwtEditablePart part, Object caretPosition) {
-       }
-
-       /** Notified when the editing state changed. Does nothing, to be overridden */
-       protected void editingStateChanged(CmsEditable cmsEditable) {
-       }
-
-       @Override
-       public void refresh() {
-               // TODO check actual context in order to notice a discrepancy
-               Subject viewerSubject = getViewerSubject();
-               Subject.doAs(viewerSubject, (PrivilegedAction<Void>) () -> {
-                       try {
-                               if (cmsEditable.canEdit() && !readOnly)
-                                       mouseListener = createMouseListener();
-                               else
-                                       mouseListener = null;
-                               refresh(getControl());
-                               // layout(getControl());
-                               if (!getControl().isDisposed())
-                                       layoutPage();
-                       } catch (RepositoryException e) {
-                               throw new JcrException("Cannot refresh", e);
-                       }
-                       return null;
-               });
-       }
-
-       @Override
-       public void setSelection(ISelection selection, boolean reveal) {
-               this.selection = selection;
-       }
-
-       protected void updateContent(SwtEditablePart part) throws RepositoryException {
-       }
-
-       // LOW LEVEL EDITION
-       protected void edit(SwtEditablePart part, Object caretPosition) {
-               try {
-                       if (edited == part)
-                               return;
-
-                       if (edited != null && edited != part) {
-                               SwtEditablePart previouslyEdited = edited;
-                               try {
-                                       stopEditing(true);
-                               } catch (Exception e) {
-                                       notifyEditionException(e);
-                                       edit(previouslyEdited, caretPosition);
-                                       return;
-                               }
-                       }
-
-                       part.startEditing();
-                       edited = part;
-                       updateContent(part);
-                       prepare(part, caretPosition);
-                       edited.getControl().addFocusListener(new FocusListener() {
-                               private static final long serialVersionUID = 6883521812717097017L;
-
-                               @Override
-                               public void focusLost(FocusEvent event) {
-                                       stopEditing(true);
-                               }
-
-                               @Override
-                               public void focusGained(FocusEvent event) {
-                               }
-                       });
-
-                       layout(part.getControl());
-                       showControl(part.getControl());
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot edit " + part, e);
-               }
-       }
-
-       protected void stopEditing(Boolean save) {
-               if (edited instanceof Widget && ((Widget) edited).isDisposed()) {
-                       edited = null;
-                       return;
-               }
-
-               assert edited != null;
-               if (edited == null) {
-                       if (log.isTraceEnabled())
-                               log.warn("Told to stop editing while not editing anything");
-                       return;
-               }
-
-               try {
-                       if (save)
-                               save(edited);
-
-                       edited.stopEditing();
-                       SwtEditablePart editablePart = edited;
-                       Control control = ((SwtEditablePart) edited).getControl();
-                       edited = null;
-                       // TODO make edited state management more robust
-                       updateContent(editablePart);
-                       layout(control);
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot stop editing", e);
-               } finally {
-                       edited = null;
-               }
-       }
-
-       // METHODS AVAILABLE TO EXTENDING CLASSES
-       protected void saveEdit() {
-               if (edited != null)
-                       stopEditing(true);
-       }
-
-       protected void cancelEdit() {
-               if (edited != null)
-                       stopEditing(false);
-       }
-
-       /** Layout this controls from the related base page. */
-       public void layout(Control... controls) {
-               page.layout(controls);
-       }
-
-       /**
-        * Find the first {@link SwtEditablePart} in the parents hierarchy of this control
-        */
-       protected SwtEditablePart findDataParent(Control parent) {
-               if (parent instanceof SwtEditablePart) {
-                       return (SwtEditablePart) parent;
-               }
-               if (parent.getParent() != null)
-                       return findDataParent(parent.getParent());
-               else
-                       throw new IllegalStateException("No data parent found");
-       }
-
-       // UTILITIES
-       /** Check whether the edited part is in a proper state */
-       protected void checkEdited() {
-               if (edited == null || (edited instanceof Widget) && ((Widget) edited).isDisposed())
-                       throw new IllegalStateException("Edited should not be null or disposed at this stage");
-       }
-
-       /** Persist all changes. */
-       protected void persistChanges(Session session) throws RepositoryException {
-               session.save();
-               session.refresh(false);
-               // TODO notify that changes have been persisted
-       }
-
-       /** Convenience method using a Node in order to save the underlying session. */
-       protected void persistChanges(Node anyNode) throws RepositoryException {
-               persistChanges(anyNode.getSession());
-       }
-
-       /** Notify edition exception */
-       protected void notifyEditionException(Throwable e) {
-               Throwable eToLog = e;
-               if (e instanceof IllegalArgumentException)
-                       if (e.getCause() instanceof SAXParseException)
-                               eToLog = e.getCause();
-               log.error(eToLog.getMessage(), eToLog);
-//             if (log.isTraceEnabled())
-//                     log.trace("Full stack of " + eToLog.getMessage(), e);
-               // TODO Light error notification popup
-       }
-
-       protected Subject getViewerSubject() {
-               Subject res = null;
-               if (accessControlContext != null) {
-                       res = Subject.getSubject(accessControlContext);
-               }
-               if (res == null)
-                       throw new IllegalStateException("No subject associated with this viewer");
-               return res;
-       }
-
-       // GETTERS / SETTERS
-       public boolean isReadOnly() {
-               return readOnly;
-       }
-
-       protected SwtEditablePart getEdited() {
-               return edited;
-       }
-
-       public MouseListener getMouseListener() {
-               return mouseListener;
-       }
-
-       public FocusListener getFocusListener() {
-               return focusListener;
-       }
-
-       public CmsEditable getCmsEditable() {
-               return cmsEditable;
-       }
-
-       @Override
-       public ISelection getSelection() {
-               return selection;
-       }
-}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/ItemPart.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/ItemPart.java
deleted file mode 100644 (file)
index 4ca45d1..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.argeo.cms.ui.viewers;
-
-import javax.jcr.Item;
-import javax.jcr.RepositoryException;
-
-/** An editable part related to a JCR Item */
-public interface ItemPart<T extends Item> {
-       public Item getItem() throws RepositoryException;
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/JcrVersionCmsEditable.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/JcrVersionCmsEditable.java
deleted file mode 100644 (file)
index 298fbde..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-package org.argeo.cms.ui.viewers;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.version.VersionManager;
-
-import org.argeo.api.cms.ux.CmsEditionEvent;
-import org.argeo.cms.ux.AbstractCmsEditable;
-import org.argeo.jcr.JcrException;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
-
-/** Provides the CmsEditable semantic based on JCR versioning. */
-public class JcrVersionCmsEditable extends AbstractCmsEditable {
-       private final String nodePath;// cache
-       private final VersionManager versionManager;
-       private final Boolean canEdit;
-
-       public JcrVersionCmsEditable(Node node) throws RepositoryException {
-               this.nodePath = node.getPath();
-               if (node.getSession().hasPermission(node.getPath(), Session.ACTION_SET_PROPERTY)) {
-                       // was Session.ACTION_ADD_NODE
-                       canEdit = true;
-                       if (!node.isNodeType(NodeType.MIX_VERSIONABLE)) {
-                               node.addMixin(NodeType.MIX_VERSIONABLE);
-                               node.getSession().save();
-                       }
-                       versionManager = node.getSession().getWorkspace().getVersionManager();
-               } else {
-                       canEdit = false;
-                       versionManager = null;
-               }
-
-               // bind keys
-               if (canEdit) {
-                       Display display = Display.getCurrent();
-                       display.setData(RWT.ACTIVE_KEYS, new String[] { "CTRL+RETURN", "CTRL+E" });
-                       display.addFilter(SWT.KeyDown, new Listener() {
-                               private static final long serialVersionUID = -4378653870463187318L;
-
-                               public void handleEvent(Event e) {
-                                       boolean ctrlPressed = (e.stateMask & SWT.CTRL) != 0;
-                                       if (ctrlPressed && e.keyCode == '\r')
-                                               stopEditing();
-                                       else if (ctrlPressed && e.keyCode == 'E')
-                                               stopEditing();
-                               }
-                       });
-               }
-       }
-
-       @Override
-       public Boolean canEdit() {
-               return canEdit;
-       }
-
-       public Boolean isEditing() {
-               try {
-                       if (!canEdit())
-                               return false;
-                       return versionManager.isCheckedOut(nodePath);
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot check whether " + nodePath + " is editing", e);
-               }
-       }
-
-       @Override
-       public void startEditing() {
-               try {
-                       versionManager.checkout(nodePath);
-//                     setChanged();
-               } catch (RepositoryException e1) {
-                       throw new JcrException("Cannot publish " + nodePath, e1);
-               }
-               notifyListeners(new CmsEditionEvent(nodePath, CmsEditionEvent.START_EDITING, this));
-       }
-
-       @Override
-       public void stopEditing() {
-               try {
-                       versionManager.checkin(nodePath);
-//                     setChanged();
-               } catch (RepositoryException e1) {
-                       throw new JcrException("Cannot publish " + nodePath, e1);
-               }
-               notifyListeners(new CmsEditionEvent(nodePath, CmsEditionEvent.STOP_EDITING, this));
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/NodePart.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/NodePart.java
deleted file mode 100644 (file)
index b51d4fc..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.argeo.cms.ui.viewers;
-
-import javax.jcr.Node;
-
-/** An editable part related to a node */
-public interface NodePart extends ItemPart<Node> {
-       public Node getNode();
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/PropertyPart.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/PropertyPart.java
deleted file mode 100644 (file)
index 793079e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.argeo.cms.ui.viewers;
-
-import javax.jcr.Property;
-
-/** An editable part related to a JCR Property */
-public interface PropertyPart extends ItemPart<Property> {
-       public Property getProperty();
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/Section.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/Section.java
deleted file mode 100644 (file)
index b27fa38..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-package org.argeo.cms.ui.viewers;
-
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.SwtEditablePart;
-import org.argeo.cms.ui.widgets.JcrComposite;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** A structured UI related to a JCR context. */
-public class Section extends JcrComposite {
-       private static final long serialVersionUID = -5933796173755739207L;
-
-       private final Section parentSection;
-       private Composite sectionHeader;
-       private final Integer relativeDepth;
-
-       public Section(Composite parent, int style, Node node) {
-               this(parent, findSection(parent), style, node);
-       }
-
-       public Section(Section section, int style, Node node) {
-               this(section, section, style, node);
-       }
-
-       protected Section(Composite parent, Section parentSection, int style, Node node) {
-               super(parent, style, node);
-               try {
-                       this.parentSection = parentSection;
-                       if (parentSection != null) {
-                               relativeDepth = getNode().getDepth() - parentSection.getNode().getDepth();
-                       } else {
-                               relativeDepth = 0;
-                       }
-                       setLayout(CmsSwtUtils.noSpaceGridLayout());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Cannot create section from " + node, e);
-               }
-       }
-
-       public Map<String, Section> getSubSections() throws RepositoryException {
-               LinkedHashMap<String, Section> result = new LinkedHashMap<String, Section>();
-               for (Control child : getChildren()) {
-                       if (child instanceof Composite) {
-                               collectDirectSubSections((Composite) child, result);
-                       }
-               }
-               return Collections.unmodifiableMap(result);
-       }
-
-       private void collectDirectSubSections(Composite composite, LinkedHashMap<String, Section> subSections)
-                       throws RepositoryException {
-               if (composite == sectionHeader || composite instanceof SwtEditablePart)
-                       return;
-               if (composite instanceof Section) {
-                       Section section = (Section) composite;
-                       subSections.put(section.getNodeId(), section);
-                       return;
-               }
-
-               for (Control child : composite.getChildren())
-                       if (child instanceof Composite)
-                               collectDirectSubSections((Composite) child, subSections);
-       }
-
-       public Composite createHeader() {
-               return createHeader(this);
-       }
-
-       public Composite createHeader(Composite parent) {
-               if (sectionHeader != null)
-                       sectionHeader.dispose();
-
-               sectionHeader = new Composite(parent, SWT.NONE);
-               sectionHeader.setLayoutData(CmsSwtUtils.fillWidth());
-               sectionHeader.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               // sectionHeader.moveAbove(null);
-               // layout();
-               return sectionHeader;
-       }
-
-       public Composite getHeader() {
-               if (sectionHeader != null && sectionHeader.isDisposed())
-                       sectionHeader = null;
-               return sectionHeader;
-       }
-
-       // SECTION PARTS
-       public SectionPart getSectionPart(String partId) {
-               for (Control child : getChildren()) {
-                       if (child instanceof SectionPart) {
-                               SectionPart sectionPart = (SectionPart) child;
-                               if (sectionPart.getPartId().equals(partId))
-                                       return sectionPart;
-                       }
-               }
-               return null;
-       }
-
-       public SectionPart nextSectionPart(SectionPart sectionPart) {
-               Control[] children = getChildren();
-               for (int i = 0; i < children.length; i++) {
-                       if (sectionPart == children[i]) {
-                               for (int j = i + 1; j < children.length; j++) {
-                                       if (children[i + 1] instanceof SectionPart) {
-                                               return (SectionPart) children[i + 1];
-                                       }
-                               }
-
-//                             if (i + 1 < children.length) {
-//                                     Composite next = (Composite) children[i + 1];
-//                                     return (SectionPart) next;
-//                             } else {
-//                                     // next section
-//                             }
-                       }
-               }
-               return null;
-       }
-
-       public SectionPart previousSectionPart(SectionPart sectionPart) {
-               Control[] children = getChildren();
-               for (int i = 0; i < children.length; i++) {
-                       if (sectionPart == children[i])
-                               if (i != 0) {
-                                       Composite previous = (Composite) children[i - 1];
-                                       return (SectionPart) previous;
-                               } else {
-                                       // previous section
-                               }
-               }
-               return null;
-       }
-
-       @Override
-       public String toString() {
-               if (parentSection == null)
-                       return "Main section " + getNode();
-               return "Section " + getNode();
-       }
-
-       public Section getParentSection() {
-               return parentSection;
-       }
-
-       public Integer getRelativeDepth() {
-               return relativeDepth;
-       }
-
-       /** Recursively finds the related section in the parents (can be itself) */
-       public static Section findSection(Control control) {
-               if (control == null)
-                       return null;
-               if (control instanceof Section)
-                       return (Section) control;
-               else
-                       return findSection(control.getParent());
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/SectionPart.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/SectionPart.java
deleted file mode 100644 (file)
index 4278c83..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.argeo.cms.ui.viewers;
-
-import org.argeo.cms.swt.SwtEditablePart;
-
-/** An editable part dynamically related to a Section */
-public interface SectionPart extends SwtEditablePart, NodePart {
-       public String getPartId();
-
-       public Section getSection();
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/package-info.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/package-info.java
deleted file mode 100644 (file)
index 2f07931..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Argeo CMS generic viewers, based on JFace. */
-package org.argeo.cms.ui.viewers;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableImage.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableImage.java
deleted file mode 100644 (file)
index 95d9e8e..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-package org.argeo.cms.ui.widgets;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.Cms2DSize;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** A stylable and editable image. */
-public abstract class EditableImage extends StyledControl {
-       private static final long serialVersionUID = -5689145523114022890L;
-       private final static CmsLog log = CmsLog.getLog(EditableImage.class);
-
-       private Cms2DSize preferredImageSize;
-       private Boolean loaded = false;
-
-       public EditableImage(Composite parent, int swtStyle) {
-               super(parent, swtStyle);
-       }
-
-       public EditableImage(Composite parent, int swtStyle, Cms2DSize preferredImageSize) {
-               super(parent, swtStyle);
-               this.preferredImageSize = preferredImageSize;
-       }
-
-       public EditableImage(Composite parent, int style, Node node, boolean cacheImmediately, Cms2DSize preferredImageSize)
-                       throws RepositoryException {
-               super(parent, style, node, cacheImmediately);
-               this.preferredImageSize = preferredImageSize;
-       }
-
-       @Override
-       protected void setContainerLayoutData(Composite composite) {
-               // composite.setLayoutData(fillWidth());
-       }
-
-       @Override
-       protected void setControlLayoutData(Control control) {
-               // control.setLayoutData(fillWidth());
-       }
-
-       /** To be overriden. */
-       protected String createImgTag() throws RepositoryException {
-               return CmsUiUtils
-                               .noImg(preferredImageSize != null ? preferredImageSize : new Cms2DSize(getSize().x, getSize().y));
-       }
-
-       protected Label createLabel(Composite box, String style) {
-               Label lbl = new Label(box, getStyle());
-               // lbl.setLayoutData(CmsUiUtils.fillWidth());
-               CmsSwtUtils.markup(lbl);
-               CmsSwtUtils.style(lbl, style);
-               if (mouseListener != null)
-                       lbl.addMouseListener(mouseListener);
-               load(lbl);
-               return lbl;
-       }
-
-       /** To be overriden. */
-       protected synchronized Boolean load(Control control) {
-               String imgTag;
-               try {
-                       imgTag = createImgTag();
-               } catch (Exception e) {
-                       // throw new CmsException("Cannot retrieve image", e);
-                       log.error("Cannot retrieve image", e);
-                       imgTag = CmsUiUtils.noImg(preferredImageSize);
-                       loaded = false;
-               }
-
-               if (imgTag == null) {
-                       loaded = false;
-                       imgTag = CmsUiUtils.noImg(preferredImageSize);
-               } else
-                       loaded = true;
-               if (control != null) {
-                       ((Label) control).setText(imgTag);
-                       control.setSize(preferredImageSize != null
-                                       ? new Point(preferredImageSize.getWidth(), preferredImageSize.getHeight())
-                                       : getSize());
-               } else {
-                       loaded = false;
-               }
-               getParent().layout();
-               return loaded;
-       }
-
-       public void setPreferredSize(Cms2DSize size) {
-               this.preferredImageSize = size;
-               if (!loaded) {
-                       load((Label) getControl());
-               }
-       }
-
-       protected Text createText(Composite box, String style) {
-               Text text = new Text(box, getStyle());
-               CmsSwtUtils.style(text, style);
-               return text;
-       }
-
-       public Cms2DSize getPreferredImageSize() {
-               return preferredImageSize;
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableText.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableText.java
deleted file mode 100644 (file)
index e3499ac..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-package org.argeo.cms.ui.widgets;
-
-import javax.jcr.Item;
-import javax.jcr.RepositoryException;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-/** Editable text part displaying styled text. */
-public class EditableText extends StyledControl {
-       private static final long serialVersionUID = -6372283442330912755L;
-
-       private boolean editable = true;
-
-       private Color highlightColor;
-       private Composite highlight;
-
-       private boolean useTextAsLabel = false;
-
-       public EditableText(Composite parent, int style) {
-               super(parent, style);
-               editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
-               highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
-       }
-
-       public EditableText(Composite parent, int style, Item item) throws RepositoryException {
-               this(parent, style, item, false);
-       }
-
-       public EditableText(Composite parent, int style, Item item, boolean cacheImmediately) throws RepositoryException {
-               super(parent, style, item, cacheImmediately);
-               editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
-               highlightColor = parent.getDisplay().getSystemColor(SWT.COLOR_GRAY);
-       }
-
-       @Override
-       protected Control createControl(Composite box, String style) {
-               if (isEditing() && getEditable()) {
-                       return createText(box, style, true);
-               } else {
-                       if (useTextAsLabel) {
-                               return createTextLabel(box, style);
-                       } else {
-                               return createLabel(box, style);
-                       }
-               }
-       }
-
-       protected Label createLabel(Composite box, String style) {
-               Label lbl = new Label(box, getStyle() | SWT.WRAP);
-               lbl.setLayoutData(CmsSwtUtils.fillWidth());
-               if (style != null)
-                       CmsSwtUtils.style(lbl, style);
-               CmsSwtUtils.markup(lbl);
-               if (mouseListener != null)
-                       lbl.addMouseListener(mouseListener);
-               return lbl;
-       }
-
-       protected Text createTextLabel(Composite box, String style) {
-               Text lbl = new Text(box, getStyle() | SWT.MULTI);
-               lbl.setEditable(false);
-               lbl.setLayoutData(CmsSwtUtils.fillWidth());
-               if (style != null)
-                       CmsSwtUtils.style(lbl, style);
-               CmsSwtUtils.markup(lbl);
-               if (mouseListener != null)
-                       lbl.addMouseListener(mouseListener);
-               return lbl;
-       }
-
-       protected Text createText(Composite box, String style, boolean editable) {
-               highlight = new Composite(box, SWT.NONE);
-               highlight.setBackground(highlightColor);
-               GridData highlightGd = new GridData(SWT.FILL, SWT.FILL, false, false);
-               highlightGd.widthHint = 5;
-               highlightGd.heightHint = 3;
-               highlight.setLayoutData(highlightGd);
-
-               final Text text = new Text(box, getStyle() | SWT.MULTI | SWT.WRAP);
-               text.setEditable(editable);
-               GridData textLayoutData = CmsSwtUtils.fillWidth();
-               // textLayoutData.heightHint = preferredHeight;
-               text.setLayoutData(textLayoutData);
-               if (style != null)
-                       CmsSwtUtils.style(text, style);
-               text.setFocus();
-               return text;
-       }
-
-       @Override
-       protected void clear(boolean deep) {
-               if (highlight != null)
-                       highlight.dispose();
-               super.clear(deep);
-       }
-
-       public void setText(String text) {
-               Control child = getControl();
-               if (child instanceof Label)
-                       ((Label) child).setText(text);
-               else if (child instanceof Text)
-                       ((Text) child).setText(text);
-       }
-
-       public Text getAsText() {
-               return (Text) getControl();
-       }
-
-       public Label getAsLabel() {
-               return (Label) getControl();
-       }
-
-       public String getText() {
-               Control child = getControl();
-
-               if (child instanceof Label)
-                       return ((Label) child).getText();
-               else if (child instanceof Text)
-                       return ((Text) child).getText();
-               else
-                       throw new IllegalStateException("Unsupported control " + child.getClass());
-       }
-
-       /** @deprecated Use {@link #isEditable()} instead. */
-       @Deprecated
-       public boolean getEditable() {
-               return isEditable();
-       }
-
-       public boolean isEditable() {
-               return editable;
-       }
-
-       public void setUseTextAsLabel(boolean useTextAsLabel) {
-               this.useTextAsLabel = useTextAsLabel;
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/Img.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/Img.java
deleted file mode 100644 (file)
index 41063fa..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-package org.argeo.cms.ui.widgets;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.ux.Cms2DSize;
-import org.argeo.api.cms.ux.CmsImageManager;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.internal.JcrFileUploadReceiver;
-import org.argeo.cms.ui.viewers.NodePart;
-import org.argeo.cms.ui.viewers.Section;
-import org.argeo.cms.ui.viewers.SectionPart;
-import org.argeo.jcr.Jcr;
-import org.argeo.jcr.JcrException;
-import org.eclipse.rap.fileupload.FileUploadHandler;
-import org.eclipse.rap.fileupload.FileUploadListener;
-import org.eclipse.rap.fileupload.FileUploadReceiver;
-import org.eclipse.rap.rwt.service.ServerPushSession;
-import org.eclipse.rap.rwt.widgets.FileUpload;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** An image within the Argeo Text framework */
-public class Img extends EditableImage implements SectionPart, NodePart {
-       private static final long serialVersionUID = 6233572783968188476L;
-
-       private final Section section;
-
-       private final CmsImageManager<Control, Node> imageManager;
-       private FileUploadHandler currentUploadHandler = null;
-       private FileUploadListener fileUploadListener;
-
-       public Img(Composite parent, int swtStyle, Node imgNode, Cms2DSize preferredImageSize) throws RepositoryException {
-               this(Section.findSection(parent), parent, swtStyle, imgNode, preferredImageSize, null);
-               setStyle(TextStyles.TEXT_IMAGE);
-       }
-
-       public Img(Composite parent, int swtStyle, Node imgNode) throws RepositoryException {
-               this(Section.findSection(parent), parent, swtStyle, imgNode, null, null);
-               setStyle(TextStyles.TEXT_IMAGE);
-       }
-
-       public Img(Composite parent, int swtStyle, Node imgNode, CmsImageManager<Control, Node> imageManager)
-                       throws RepositoryException {
-               this(Section.findSection(parent), parent, swtStyle, imgNode, null, imageManager);
-               setStyle(TextStyles.TEXT_IMAGE);
-       }
-
-       Img(Section section, Composite parent, int swtStyle, Node imgNode, Cms2DSize preferredImageSize,
-                       CmsImageManager<Control, Node> imageManager) throws RepositoryException {
-               super(parent, swtStyle, imgNode, false, preferredImageSize);
-               this.section = section;
-               this.imageManager = imageManager != null ? imageManager
-                               : (CmsImageManager<Control, Node>) CmsSwtUtils.getCmsView(section).getImageManager();
-               CmsSwtUtils.style(this, TextStyles.TEXT_IMG);
-       }
-
-       @Override
-       protected Control createControl(Composite box, String style) {
-               if (isEditing()) {
-                       try {
-                               return createImageChooser(box, style);
-                       } catch (RepositoryException e) {
-                               throw new JcrException("Cannot create image chooser", e);
-                       }
-               } else {
-                       return createLabel(box, style);
-               }
-       }
-
-       @Override
-       public synchronized void stopEditing() {
-               super.stopEditing();
-               fileUploadListener = null;
-       }
-
-       @Override
-       protected synchronized Boolean load(Control lbl) {
-               Node imgNode = getNode();
-               boolean loaded = imageManager.load(imgNode, lbl, getPreferredImageSize());
-               // getParent().layout();
-               return loaded;
-       }
-
-       protected Node getUploadFolder() {
-               return Jcr.getParent(getNode());
-       }
-
-       protected String getUploadName() {
-               Node node = getNode();
-               return Jcr.getName(node) + '[' + Jcr.getIndex(node) + ']';
-       }
-
-       protected CmsImageManager<Control, Node> getImageManager() {
-               return imageManager;
-       }
-
-       protected Control createImageChooser(Composite box, String style) throws RepositoryException {
-               JcrFileUploadReceiver receiver = new JcrFileUploadReceiver(this, getUploadFolder(), getUploadName(),
-                               imageManager);
-               if (currentUploadHandler != null)
-                       currentUploadHandler.dispose();
-               currentUploadHandler = prepareUpload(receiver);
-               final ServerPushSession pushSession = new ServerPushSession();
-               final FileUpload fileUpload = new FileUpload(box, SWT.NONE);
-               CmsSwtUtils.style(fileUpload, style);
-               fileUpload.addSelectionListener(new SelectionAdapter() {
-                       private static final long serialVersionUID = -9158471843941668562L;
-
-                       @Override
-                       public void widgetSelected(SelectionEvent e) {
-                               pushSession.start();
-                               fileUpload.submit(currentUploadHandler.getUploadUrl());
-                       }
-               });
-               return fileUpload;
-       }
-
-       protected FileUploadHandler prepareUpload(FileUploadReceiver receiver) {
-               final FileUploadHandler uploadHandler = new FileUploadHandler(receiver);
-               if (fileUploadListener != null)
-                       uploadHandler.addUploadListener(fileUploadListener);
-               return uploadHandler;
-       }
-
-       @Override
-       public Section getSection() {
-               return section;
-       }
-
-       public void setFileUploadListener(FileUploadListener fileUploadListener) {
-               this.fileUploadListener = fileUploadListener;
-               if (currentUploadHandler != null)
-                       currentUploadHandler.addUploadListener(fileUploadListener);
-       }
-
-       @Override
-       public Node getItem() throws RepositoryException {
-               return getNode();
-       }
-
-       @Override
-       public String getPartId() {
-               return getNodeId();
-       }
-
-       @Override
-       public String toString() {
-               return "Img #" + getPartId();
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java
deleted file mode 100644 (file)
index 6b54c0a..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-package org.argeo.cms.ui.widgets;
-
-import javax.jcr.Item;
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.jcr.JcrException;
-import org.eclipse.swt.widgets.Composite;
-
-/** A composite which can (optionally) manage a JCR Item. */
-public class JcrComposite extends Composite {
-       private static final long serialVersionUID = -1447009015451153367L;
-
-       private Session session;
-
-       private String nodeId;
-       private String property = null;
-       private Node cache;
-
-       /** Regular composite constructor. No layout is set. */
-       public JcrComposite(Composite parent, int style) {
-               super(parent, style);
-               session = null;
-               nodeId = null;
-       }
-
-       public JcrComposite(Composite parent, int style, Item item) {
-               this(parent, style, item, false);
-       }
-
-       public JcrComposite(Composite parent, int style, Item item, boolean cacheImmediately) {
-               super(parent, style);
-               if (item != null)
-                       try {
-                               this.session = item.getSession();
-//                             if (!cacheImmediately && (SWT.READ_ONLY == (style & SWT.READ_ONLY))) {
-//                                     // (useless?) optimization: we only save a pointer to the session,
-//                                     // not even a reference to the item
-//                                     this.nodeId = null;
-//                             } else {
-                               Node node;
-                               Property property = null;
-                               if (item instanceof Node) {
-                                       node = (Node) item;
-                               } else {// Property
-                                       property = (Property) item;
-                                       if (property.isMultiple())// TODO manage property index
-                                               throw new UnsupportedOperationException("Multiple properties not supported yet.");
-                                       this.property = property.getName();
-                                       node = property.getParent();
-                               }
-                               this.nodeId = node.getIdentifier();
-                               if (cacheImmediately)
-                                       this.cache = node;
-//                             }
-                               setLayout(CmsSwtUtils.noSpaceGridLayout());
-                       } catch (RepositoryException e) {
-                               throw new IllegalStateException("Cannot create composite from " + item, e);
-                       }
-       }
-
-       public synchronized Node getNode() {
-               try {
-                       if (!itemIsNode())
-                               throw new IllegalStateException("Item is not a Node");
-                       return getNodeInternal();
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot get node " + nodeId, e);
-               }
-       }
-
-       private synchronized Node getNodeInternal() throws RepositoryException {
-               if (cache != null)
-                       return cache;
-               else if (session != null)
-                       if (nodeId != null)
-                               return session.getNodeByIdentifier(nodeId);
-                       else
-                               return null;
-               else
-                       return null;
-       }
-
-       public synchronized String getPropertyName() {
-               try {
-                       return getProperty().getName();
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot get property name", e);
-               }
-       }
-
-       public synchronized Node getPropertyNode() {
-               try {
-                       return getProperty().getNode();
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot get property name", e);
-               }
-       }
-
-       public synchronized Property getProperty() {
-               try {
-                       if (itemIsNode())
-                               throw new IllegalStateException("Item is not a Property");
-                       Node node = getNodeInternal();
-                       if (!node.hasProperty(property))
-                               throw new IllegalStateException("Property " + property + " is not set on " + node);
-                       return node.getProperty(property);
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot get property " + property + " from node " + nodeId, e);
-               }
-       }
-
-       public synchronized boolean itemIsNode() {
-               return property == null;
-       }
-
-       public synchronized boolean itemExists() {
-               if (session == null)
-                       return false;
-               try {
-                       Node n = session.getNodeByIdentifier(nodeId);
-                       if (!itemIsNode())
-                               return n.hasProperty(property);
-                       else
-                               return true;
-               } catch (ItemNotFoundException e) {
-                       return false;
-               } catch (RepositoryException e) {
-                       throw new JcrException("Cannot check whether node exists", e);
-               }
-       }
-
-       /** Set/update the cache or change the node */
-       public synchronized void setNode(Node node) {
-               if (!itemIsNode())
-                       throw new IllegalArgumentException("Cannot set a Node on a Property");
-
-               if (node == null) {// clear cache
-                       this.cache = null;
-                       return;
-               }
-
-               try {
-//                     if (session != null || session != node.getSession())// check session
-//                             throw new IllegalArgumentException("Uncompatible session");
-//                     if (session == null)
-                       session = node.getSession();
-                       if (nodeId == null || !nodeId.equals(node.getIdentifier())) {
-                               nodeId = node.getIdentifier();
-                               cache = node;
-                               itemUpdated();
-                       } else {
-                               cache = node;// set/update cache
-                       }
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException(e);
-               }
-       }
-
-       /** Set/update the cache or change the property */
-       public synchronized void setProperty(Property prop) {
-               if (itemIsNode())
-                       throw new IllegalArgumentException("Cannot set a Property on a Node");
-
-               if (prop == null) {// clear cache
-                       this.cache = null;
-                       return;
-               }
-
-               try {
-                       if (session == null || session != prop.getSession())// check session
-                               throw new IllegalArgumentException("Uncompatible session");
-
-                       Node node = prop.getNode();
-                       if (nodeId == null || !nodeId.equals(node.getIdentifier()) || !property.equals(prop.getName())) {
-                               nodeId = node.getIdentifier();
-                               property = prop.getName();
-                               cache = node;
-                               itemUpdated();
-                       } else {
-                               cache = node;// set/update cache
-                       }
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException(e);
-               }
-       }
-
-       public synchronized String getNodeId() {
-               return nodeId;
-       }
-
-       /** Change the node, does nothing if same. */
-       public synchronized void setNodeId(String nodeId) throws RepositoryException {
-               if (this.nodeId != null && this.nodeId.equals(nodeId))
-                       return;
-               this.nodeId = nodeId;
-               if (cache != null)
-                       cache = session.getNodeByIdentifier(this.nodeId);
-               itemUpdated();
-       }
-
-       protected synchronized void itemUpdated() {
-               layout();
-       }
-
-//     public Session getSession() {
-//             return session;
-//     }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/StyledControl.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/StyledControl.java
deleted file mode 100644 (file)
index e3a5cb4..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-package org.argeo.cms.ui.widgets;
-
-import javax.jcr.Item;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.CmsUiConstants;
-import org.argeo.eclipse.ui.specific.EclipseUiSpecificUtils;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.FocusListener;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Editable text part displaying styled text. */
-public abstract class StyledControl extends JcrComposite implements CmsUiConstants {
-       private static final long serialVersionUID = -6372283442330912755L;
-       private Control control;
-
-       private Composite container;
-       private Composite box;
-
-       protected MouseListener mouseListener;
-       protected FocusListener focusListener;
-
-       private Boolean editing = Boolean.FALSE;
-
-       private Composite ancestorToLayout;
-
-       public StyledControl(Composite parent, int swtStyle) {
-               super(parent, swtStyle);
-               setLayout(CmsSwtUtils.noSpaceGridLayout());
-       }
-
-       public StyledControl(Composite parent, int style, Item item) {
-               super(parent, style, item);
-       }
-
-       public StyledControl(Composite parent, int style, Item item, boolean cacheImmediately) {
-               super(parent, style, item, cacheImmediately);
-       }
-
-       protected abstract Control createControl(Composite box, String style);
-
-       protected Composite createBox() {
-               Composite box = new Composite(container, SWT.INHERIT_DEFAULT);
-               setContainerLayoutData(box);
-               box.setLayout(CmsSwtUtils.noSpaceGridLayout(3));
-               return box;
-       }
-
-       protected Composite createContainer() {
-               Composite container = new Composite(this, SWT.INHERIT_DEFAULT);
-               setContainerLayoutData(container);
-               container.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               return container;
-       }
-
-       public Control getControl() {
-               return control;
-       }
-
-       protected synchronized Boolean isEditing() {
-               return editing;
-       }
-
-       public synchronized void startEditing() {
-               assert !isEditing();
-               editing = true;
-               // int height = control.getSize().y;
-               String style = (String) EclipseUiSpecificUtils.getStyleData(control);
-               clear(false);
-               refreshControl(style);
-
-               // add the focus listener to the newly created edition control
-               if (focusListener != null)
-                       control.addFocusListener(focusListener);
-       }
-
-       public synchronized void stopEditing() {
-               assert isEditing();
-               editing = false;
-               String style = (String) EclipseUiSpecificUtils.getStyleData(control);
-               clear(false);
-               refreshControl(style);
-       }
-
-       protected void refreshControl(String style) {
-               control = createControl(box, style);
-               setControlLayoutData(control);
-               if (ancestorToLayout != null)
-                       ancestorToLayout.layout(true, true);
-               else
-                       getParent().layout(true, true);
-       }
-
-       public void setStyle(String style) {
-               Object currentStyle = null;
-               if (control != null)
-                       currentStyle = EclipseUiSpecificUtils.getStyleData(control);
-               if (currentStyle != null && currentStyle.equals(style))
-                       return;
-
-               clear(true);
-               refreshControl(style);
-
-               if (style != null) {
-                       CmsSwtUtils.style(box, style + "_box");
-                       CmsSwtUtils.style(container, style + "_container");
-               }
-       }
-
-       /** To be overridden */
-       protected void setControlLayoutData(Control control) {
-               control.setLayoutData(CmsSwtUtils.fillWidth());
-       }
-
-       /** To be overridden */
-       protected void setContainerLayoutData(Composite composite) {
-               composite.setLayoutData(CmsSwtUtils.fillWidth());
-       }
-
-       protected void clear(boolean deep) {
-               if (deep) {
-                       for (Control control : getChildren())
-                               control.dispose();
-                       container = createContainer();
-                       box = createBox();
-               } else {
-                       control.dispose();
-               }
-       }
-
-       public void setMouseListener(MouseListener mouseListener) {
-               if (this.mouseListener != null && control != null)
-                       control.removeMouseListener(this.mouseListener);
-               this.mouseListener = mouseListener;
-               if (control != null && this.mouseListener != null)
-                       control.addMouseListener(mouseListener);
-       }
-
-       public void setFocusListener(FocusListener focusListener) {
-               if (this.focusListener != null && control != null)
-                       control.removeFocusListener(this.focusListener);
-               this.focusListener = focusListener;
-               if (control != null && this.focusListener != null)
-                       control.addFocusListener(focusListener);
-       }
-
-       public void setAncestorToLayout(Composite ancestorToLayout) {
-               this.ancestorToLayout = ancestorToLayout;
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/TextStyles.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/TextStyles.java
deleted file mode 100644 (file)
index e461ed0..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.argeo.cms.ui.widgets;
-
-/** Styles references in the CSS. */
-public interface TextStyles {
-       /** The whole page area */
-       public final static String TEXT_AREA = "text_area";
-       /** Area providing controls for editing text */
-       public final static String TEXT_EDITOR_HEADER = "text_editor_header";
-       /** The styled composite for editing the text */
-       public final static String TEXT_STYLED_COMPOSITE = "text_styled_composite";
-       /** A section */
-       public final static String TEXT_SECTION = "text_section";
-       /** A paragraph */
-       public final static String TEXT_PARAGRAPH = "text_paragraph";
-       /** An image */
-       public final static String TEXT_IMG = "text_img";
-       /** The dialog to edit styled paragraph */
-       public final static String TEXT_STYLED_TOOLS_DIALOG = "text_styled_tools_dialog";
-
-       /*
-        * DEFAULT TEXT STYLES
-        */
-       /** Default style for text body */
-       public final static String TEXT_DEFAULT = "text_default";
-       /** Fixed-width, typically code */
-       public final static String TEXT_PRE = "text_pre";
-       /** Quote */
-       public final static String TEXT_QUOTE = "text_quote";
-       /** Title */
-       public final static String TEXT_TITLE = "text_title";
-       /** Header (to be dynamically completed with the depth, e.g. text_h1) */
-       public final static String TEXT_H = "text_h";
-
-       /** Default style for images */
-       public final static String TEXT_IMAGE = "text_image";
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/package-info.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/package-info.java
deleted file mode 100644 (file)
index 514f753..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Argeo CMS generic widgets, based on SWT. */
-package org.argeo.cms.ui.widgets;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/AbstractNodeContentProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/AbstractNodeContentProvider.java
deleted file mode 100644 (file)
index fdafa98..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.eclipse.ui.AbstractTreeContentProvider;
-import org.argeo.eclipse.ui.EclipseUiException;
-
-/** Canonical implementation of tree content provider manipulating JCR nodes. */
-public abstract class AbstractNodeContentProvider extends
-               AbstractTreeContentProvider {
-       private static final long serialVersionUID = -4905836490027272569L;
-
-       private final static CmsLog log = CmsLog
-                       .getLog(AbstractNodeContentProvider.class);
-
-       private Session session;
-
-       public AbstractNodeContentProvider(Session session) {
-               this.session = session;
-       }
-
-       /**
-        * Whether this path is a base path (and thus has no parent). By default it
-        * returns true if path is '/' (root node)
-        */
-       protected Boolean isBasePath(String path) {
-               // root node
-               return path.equals("/");
-       }
-
-       @Override
-       public Object[] getChildren(Object element) {
-               Object[] children;
-               if (element instanceof Node) {
-                       try {
-                               Node node = (Node) element;
-                               children = getChildren(node);
-                       } catch (RepositoryException e) {
-                               throw new EclipseUiException("Cannot get children of " + element, e);
-                       }
-               } else if (element instanceof WrappedNode) {
-                       WrappedNode wrappedNode = (WrappedNode) element;
-                       try {
-                               children = getChildren(wrappedNode.getNode());
-                       } catch (RepositoryException e) {
-                               throw new EclipseUiException("Cannot get children of "
-                                               + wrappedNode, e);
-                       }
-               } else if (element instanceof NodesWrapper) {
-                       NodesWrapper node = (NodesWrapper) element;
-                       children = node.getChildren();
-               } else {
-                       children = super.getChildren(element);
-               }
-
-               children = sort(element, children);
-               return children;
-       }
-
-       /** Do not sort by default. To be overidden to provide custom sort. */
-       protected Object[] sort(Object parent, Object[] children) {
-               return children;
-       }
-
-       /**
-        * To be overridden in order to filter out some nodes. Does nothing by
-        * default. The provided list is a temporary one and can thus be modified
-        * directly . (e.g. via an iterator)
-        */
-       protected List<Node> filterChildren(List<Node> children)
-                       throws RepositoryException {
-               return children;
-       }
-
-       protected Object[] getChildren(Node node) throws RepositoryException {
-               List<Node> nodes = new ArrayList<Node>();
-               for (NodeIterator nit = node.getNodes(); nit.hasNext();)
-                       nodes.add(nit.nextNode());
-               nodes = filterChildren(nodes);
-               return nodes.toArray();
-       }
-
-       @Override
-       public Object getParent(Object element) {
-               if (element instanceof Node) {
-                       Node node = (Node) element;
-                       try {
-                               String path = node.getPath();
-                               if (isBasePath(path))
-                                       return null;
-                               else
-                                       return node.getParent();
-                       } catch (RepositoryException e) {
-                               log.warn("Cannot get parent of " + element + ": " + e);
-                               return null;
-                       }
-               } else if (element instanceof WrappedNode) {
-                       WrappedNode wrappedNode = (WrappedNode) element;
-                       return wrappedNode.getParent();
-               } else if (element instanceof NodesWrapper) {
-                       NodesWrapper nodesWrapper = (NodesWrapper) element;
-                       return this.getParent(nodesWrapper.getNode());
-               }
-               return super.getParent(element);
-       }
-
-       @Override
-       public boolean hasChildren(Object element) {
-               try {
-                       if (element instanceof Node) {
-                               Node node = (Node) element;
-                               return node.hasNodes();
-                       } else if (element instanceof WrappedNode) {
-                               WrappedNode wrappedNode = (WrappedNode) element;
-                               return wrappedNode.getNode().hasNodes();
-                       } else if (element instanceof NodesWrapper) {
-                               NodesWrapper nodesWrapper = (NodesWrapper) element;
-                               return nodesWrapper.hasChildren();
-                       }
-
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot check whether " + element
-                                       + " has children", e);
-               }
-               return super.hasChildren(element);
-       }
-
-       public Session getSession() {
-               return session;
-       }
-}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/AsyncUiEventListener.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/AsyncUiEventListener.java
deleted file mode 100644 (file)
index b880a63..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.observation.Event;
-import javax.jcr.observation.EventIterator;
-import javax.jcr.observation.EventListener;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.swt.widgets.Display;
-
-/**
- * {@link EventListener} which simplifies running actions within the UI thread.
- */
-public abstract class AsyncUiEventListener implements EventListener {
-       // private final static Log logSuper = LogFactory
-       // .getLog(AsyncUiEventListener.class);
-       private final CmsLog logThis = CmsLog.getLog(getClass());
-
-       private final Display display;
-
-       public AsyncUiEventListener(Display display) {
-               super();
-               this.display = display;
-       }
-
-       /** Called asynchronously in the UI thread. */
-       protected abstract void onEventInUiThread(List<Event> events) throws RepositoryException;
-
-       /**
-        * Whether these events should be processed in the UI or skipped with no UI
-        * job created.
-        */
-       protected Boolean willProcessInUiThread(List<Event> events) throws RepositoryException {
-               return true;
-       }
-
-       protected CmsLog getLog() {
-               return logThis;
-       }
-
-       public final void onEvent(final EventIterator eventIterator) {
-               final List<Event> events = new ArrayList<Event>();
-               while (eventIterator.hasNext())
-                       events.add(eventIterator.nextEvent());
-
-               if (logThis.isTraceEnabled())
-                       logThis.trace("Received " + events.size() + " events");
-
-               try {
-                       if (!willProcessInUiThread(events))
-                               return;
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot test skip events " + events, e);
-               }
-
-               // Job job = new Job("JCR Events") {
-               // protected IStatus run(IProgressMonitor monitor) {
-               // if (display.isDisposed()) {
-               // logSuper.warn("Display is disposed cannot update UI");
-               // return Status.CANCEL_STATUS;
-               // }
-
-               if (!display.isDisposed())
-                       display.asyncExec(new Runnable() {
-                               public void run() {
-                                       try {
-                                               onEventInUiThread(events);
-                                       } catch (RepositoryException e) {
-                                               throw new EclipseUiException("Cannot process events " + events, e);
-                                       }
-                               }
-                       });
-
-               // return Status.OK_STATUS;
-               // }
-               // };
-               // job.schedule();
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/DefaultNodeLabelProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/DefaultNodeLabelProvider.java
deleted file mode 100644 (file)
index 22ffeaf..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.swt.graphics.Image;
-
-/**
- * Default label provider to manage node and corresponding UI objects. It
- * provides reasonable overwrite-able default for known JCR types.
- */
-public class DefaultNodeLabelProvider extends ColumnLabelProvider {
-       private static final long serialVersionUID = 1216182332792151235L;
-
-       public String getText(Object element) {
-               try {
-                       if (element instanceof Node) {
-                               return getText((Node) element);
-                       } else if (element instanceof WrappedNode) {
-                               return getText(((WrappedNode) element).getNode());
-                       } else if (element instanceof NodesWrapper) {
-                               return getText(((NodesWrapper) element).getNode());
-                       }
-                       return super.getText(element);
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot get text for of " + element, e);
-               }
-       }
-
-       protected String getText(Node node) throws RepositoryException {
-               if (node.isNodeType(NodeType.MIX_TITLE)
-                               && node.hasProperty(Property.JCR_TITLE))
-                       return node.getProperty(Property.JCR_TITLE).getString();
-               else
-                       return node.getName();
-       }
-
-       @Override
-       public Image getImage(Object element) {
-               try {
-                       if (element instanceof Node) {
-                               return getImage((Node) element);
-                       } else if (element instanceof WrappedNode) {
-                               return getImage(((WrappedNode) element).getNode());
-                       } else if (element instanceof NodesWrapper) {
-                               return getImage(((NodesWrapper) element).getNode());
-                       }
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot retrieve image for " + element, e);
-               }
-               return super.getImage(element);
-       }
-
-       protected Image getImage(Node node) throws RepositoryException {
-               // FIXME who uses that?
-               return null;
-       }
-
-       @Override
-       public String getToolTipText(Object element) {
-               try {
-                       if (element instanceof Node) {
-                               return getToolTipText((Node) element);
-                       } else if (element instanceof WrappedNode) {
-                               return getToolTipText(((WrappedNode) element).getNode());
-                       } else if (element instanceof NodesWrapper) {
-                               return getToolTipText(((NodesWrapper) element).getNode());
-                       }
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot get tooltip for " + element, e);
-               }
-               return super.getToolTipText(element);
-       }
-
-       protected String getToolTipText(Node node) throws RepositoryException {
-               return null;
-       }
-}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/JcrUiUtils.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/JcrUiUtils.java
deleted file mode 100644 (file)
index 420154b..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import java.util.Calendar;
-
-import javax.jcr.Node;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.jcr.lists.NodeViewerComparator;
-import org.argeo.eclipse.ui.jcr.lists.RowViewerComparator;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.widgets.Table;
-
-/** Utility methods to simplify UI development using SWT (or RWT), jface  and JCR. */
-public class JcrUiUtils {
-
-       /**
-        * Centralizes management of updating property value. Among other to avoid
-        * infinite loop when the new value is the same as the ones that is already
-        * stored in JCR.
-        * 
-        * @return true if the value as changed
-        */
-       public static boolean setJcrProperty(Node node, String propName,
-                       int propertyType, Object value) {
-               try {
-                       switch (propertyType) {
-                       case PropertyType.STRING:
-                               if ("".equals((String) value)
-                                               && (!node.hasProperty(propName) || node
-                                                               .hasProperty(propName)
-                                                               && "".equals(node.getProperty(propName)
-                                                                               .getString())))
-                                       // workaround the fact that the Text widget value cannot be
-                                       // set to null
-                                       return false;
-                               else if (node.hasProperty(propName)
-                                               && node.getProperty(propName).getString()
-                                                               .equals((String) value))
-                                       // nothing changed yet
-                                       return false;
-                               else {
-                                       node.setProperty(propName, (String) value);
-                                       return true;
-                               }
-                       case PropertyType.BOOLEAN:
-                               if (node.hasProperty(propName)
-                                               && node.getProperty(propName).getBoolean() == (Boolean) value)
-                                       // nothing changed yet
-                                       return false;
-                               else {
-                                       node.setProperty(propName, (Boolean) value);
-                                       return true;
-                               }
-                       case PropertyType.DATE:
-                               if (node.hasProperty(propName)
-                                               && node.getProperty(propName).getDate()
-                                                               .equals((Calendar) value))
-                                       // nothing changed yet
-                                       return false;
-                               else {
-                                       node.setProperty(propName, (Calendar) value);
-                                       return true;
-                               }
-                       case PropertyType.LONG:
-                               Long lgValue = (Long) value;
-
-                               if (lgValue == null)
-                                       lgValue = 0L;
-
-                               if (node.hasProperty(propName)
-                                               && node.getProperty(propName).getLong() == lgValue)
-                                       // nothing changed yet
-                                       return false;
-                               else {
-                                       node.setProperty(propName, lgValue);
-                                       return true;
-                               }
-
-                       default:
-                               throw new EclipseUiException("Unimplemented property save");
-                       }
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Unexpected error while setting property",
-                                       re);
-               }
-       }
-
-       /**
-        * Creates a new selection adapter in order to provide sorting abitily on a
-        * SWT Table that display a row list
-        **/
-       public static SelectionAdapter getRowSelectionAdapter(final int index,
-                       final int propertyType, final String selectorName,
-                       final String propertyName, final RowViewerComparator comparator,
-                       final TableViewer viewer) {
-               SelectionAdapter selectionAdapter = new SelectionAdapter() {
-                       private static final long serialVersionUID = -5738918304901437720L;
-
-                       @Override
-                       public void widgetSelected(SelectionEvent e) {
-                               Table table = viewer.getTable();
-                               comparator.setColumn(propertyType, selectorName, propertyName);
-                               int dir = table.getSortDirection();
-                               if (table.getSortColumn() == table.getColumn(index)) {
-                                       dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
-                               } else {
-                                       dir = SWT.DOWN;
-                               }
-                               table.setSortDirection(dir);
-                               table.setSortColumn(table.getColumn(index));
-                               viewer.refresh();
-                       }
-               };
-               return selectionAdapter;
-       }
-
-       /**
-        * Creates a new selection adapter in order to provide sorting abitily on a
-        * swt table that display a row list
-        **/
-       public static SelectionAdapter getNodeSelectionAdapter(final int index,
-                       final int propertyType, final String propertyName,
-                       final NodeViewerComparator comparator, final TableViewer viewer) {
-               SelectionAdapter selectionAdapter = new SelectionAdapter() {
-                       private static final long serialVersionUID = -1683220869195484625L;
-
-                       @Override
-                       public void widgetSelected(SelectionEvent e) {
-                               Table table = viewer.getTable();
-                               comparator.setColumn(propertyType, propertyName);
-                               int dir = table.getSortDirection();
-                               if (table.getSortColumn() == table.getColumn(index)) {
-                                       dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
-                               } else {
-                                       dir = SWT.DOWN;
-                               }
-                               table.setSortDirection(dir);
-                               table.setSortColumn(table.getColumn(index));
-                               viewer.refresh();
-                       }
-               };
-               return selectionAdapter;
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/NodeColumnLabelProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/NodeColumnLabelProvider.java
deleted file mode 100644 (file)
index 7e12bec..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.Font;
-import org.eclipse.swt.graphics.Image;
-
-/** Simplifies writing JCR-based column label provider. */
-public class NodeColumnLabelProvider extends ColumnLabelProvider {
-       private static final long serialVersionUID = -6586692836928505358L;
-
-       protected String getNodeText(Node node) throws RepositoryException {
-               return super.getText(node);
-       }
-
-       protected String getNodeToolTipText(Node node) throws RepositoryException {
-               return super.getToolTipText(node);
-       }
-
-       protected Image getNodeImage(Node node) throws RepositoryException {
-               return super.getImage(node);
-       }
-
-       protected Font getNodeFont(Node node) throws RepositoryException {
-               return super.getFont(node);
-       }
-
-       public Color getNodeBackground(Node node) throws RepositoryException {
-               return super.getBackground(node);
-       }
-
-       public Color getNodeForeground(Node node) throws RepositoryException {
-               return super.getForeground(node);
-       }
-
-       @Override
-       public String getText(Object element) {
-               try {
-                       if (element instanceof Node)
-                               return getNodeText((Node) element);
-                       else if (element instanceof NodeElement)
-                               return getNodeText(((NodeElement) element).getNode());
-                       else
-                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Repository exception when accessing " + element, e);
-               }
-       }
-
-       @Override
-       public Image getImage(Object element) {
-               try {
-                       if (element instanceof Node)
-                               return getNodeImage((Node) element);
-                       else if (element instanceof NodeElement)
-                               return getNodeImage(((NodeElement) element).getNode());
-                       else
-                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Repository exception when accessing " + element, e);
-               }
-       }
-
-       @Override
-       public String getToolTipText(Object element) {
-               try {
-                       if (element instanceof Node)
-                               return getNodeToolTipText((Node) element);
-                       else if (element instanceof NodeElement)
-                               return getNodeToolTipText(((NodeElement) element).getNode());
-                       else
-                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Repository exception when accessing " + element, e);
-               }
-       }
-
-       @Override
-       public Font getFont(Object element) {
-               try {
-                       if (element instanceof Node)
-                               return getNodeFont((Node) element);
-                       else if (element instanceof NodeElement)
-                               return getNodeFont(((NodeElement) element).getNode());
-                       else
-                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Repository exception when accessing " + element, e);
-               }
-       }
-
-       @Override
-       public Color getBackground(Object element) {
-               try {
-                       if (element instanceof Node)
-                               return getNodeBackground((Node) element);
-                       else if (element instanceof NodeElement)
-                               return getNodeBackground(((NodeElement) element).getNode());
-                       else
-                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Repository exception when accessing " + element, e);
-               }
-       }
-
-       @Override
-       public Color getForeground(Object element) {
-               try {
-                       if (element instanceof Node)
-                               return getNodeForeground((Node) element);
-                       else if (element instanceof NodeElement)
-                               return getNodeForeground(((NodeElement) element).getNode());
-                       else
-                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Repository exception when accessing " + element, e);
-               }
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/NodeElement.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/NodeElement.java
deleted file mode 100644 (file)
index 787c92e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import javax.jcr.Node;
-
-/** An element which is related to a JCR {@link Node}. */
-public interface NodeElement {
-       Node getNode();
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/NodeElementComparer.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/NodeElementComparer.java
deleted file mode 100644 (file)
index 2f3d64d..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.argeo.eclipse.ui.jcr;\r
-\r
-import javax.jcr.Node;\r
-import javax.jcr.RepositoryException;\r
-\r
-import org.argeo.eclipse.ui.EclipseUiException;\r
-import org.eclipse.jface.viewers.IElementComparer;\r
-\r
-/** Element comparer for JCR node, to be used in JFace viewers. */\r
-public class NodeElementComparer implements IElementComparer {\r
-\r
-       public boolean equals(Object a, Object b) {\r
-               try {\r
-                       if ((a instanceof Node) && (b instanceof Node)) {\r
-                               Node nodeA = (Node) a;\r
-                               Node nodeB = (Node) b;\r
-                               return nodeA.getIdentifier().equals(nodeB.getIdentifier());\r
-                       } else {\r
-                               return a.equals(b);\r
-                       }\r
-               } catch (RepositoryException e) {\r
-                       throw new EclipseUiException("Cannot compare nodes", e);\r
-               }\r
-       }\r
-\r
-       public int hashCode(Object element) {\r
-               try {\r
-                       if (element instanceof Node)\r
-                               return ((Node) element).getIdentifier().hashCode();\r
-                       return element.hashCode();\r
-               } catch (RepositoryException e) {\r
-                       throw new EclipseUiException("Cannot get hash code", e);\r
-               }\r
-       }\r
-\r
-}\r
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/NodesWrapper.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/NodesWrapper.java
deleted file mode 100644 (file)
index 2f808a5..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-
-/**
- * Element of tree which is based on a node, but whose children are not
- * necessarily this node children.
- */
-public class NodesWrapper {
-       private final Node node;
-
-       public NodesWrapper(Node node) {
-               super();
-               this.node = node;
-       }
-
-       protected NodeIterator getNodeIterator() throws RepositoryException {
-               return node.getNodes();
-       }
-
-       protected List<WrappedNode> getWrappedNodes() throws RepositoryException {
-               List<WrappedNode> nodes = new ArrayList<WrappedNode>();
-               for (NodeIterator nit = getNodeIterator(); nit.hasNext();)
-                       nodes.add(new WrappedNode(this, nit.nextNode()));
-               return nodes;
-       }
-
-       public Object[] getChildren() {
-               try {
-                       return getWrappedNodes().toArray();
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot get wrapped children", e);
-               }
-       }
-
-       /**
-        * @return true by default because we don't want to compute the wrapped
-        *         nodes twice
-        */
-       public Boolean hasChildren() {
-               return true;
-       }
-
-       public Node getNode() {
-               return node;
-       }
-
-       @Override
-       public int hashCode() {
-               return node.hashCode();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (obj instanceof NodesWrapper)
-                       return node.equals(((NodesWrapper) obj).getNode());
-               else
-                       return false;
-       }
-
-       public String toString() {
-               return "nodes wrapper based on " + node;
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/QueryTableContentProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/QueryTableContentProvider.java
deleted file mode 100644 (file)
index 934fa67..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.query.Query;
-
-import org.argeo.jcr.JcrException;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.Viewer;
-
-/** Content provider based on a JCR {@link Query}. */
-public class QueryTableContentProvider implements IStructuredContentProvider {
-       private static final long serialVersionUID = 760371460907204722L;
-
-       @Override
-       public void dispose() {
-       }
-
-       @Override
-       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-       }
-
-       @Override
-       public Object[] getElements(Object inputElement) {
-               Query query = (Query) inputElement;
-               try {
-                       NodeIterator nit = query.execute().getNodes();
-                       return JcrUtils.nodeIteratorToList(nit).toArray();
-               } catch (RepositoryException e) {
-                       throw new JcrException(e);
-               }
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/RowColumnLabelProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/RowColumnLabelProvider.java
deleted file mode 100644 (file)
index 70c71ef..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.query.Row;
-
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.Font;
-import org.eclipse.swt.graphics.Image;
-
-/** Simplifies writing JCR-based column label provider. */
-public class RowColumnLabelProvider extends ColumnLabelProvider {
-       private static final long serialVersionUID = -6586692836928505358L;
-
-       protected String getRowText(Row row) throws RepositoryException {
-               return super.getText(row);
-       }
-
-       protected String getRowToolTipText(Row row) throws RepositoryException {
-               return super.getToolTipText(row);
-       }
-
-       protected Image getRowImage(Row row) throws RepositoryException {
-               return super.getImage(row);
-       }
-
-       protected Font getRowFont(Row row) throws RepositoryException {
-               return super.getFont(row);
-       }
-
-       public Color getRowBackground(Row row) throws RepositoryException {
-               return super.getBackground(row);
-       }
-
-       public Color getRowForeground(Row row) throws RepositoryException {
-               return super.getForeground(row);
-       }
-
-       @Override
-       public String getText(Object element) {
-               try {
-                       if (element instanceof Row)
-                               return getRowText((Row) element);
-                       else
-                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Repository exception when accessing " + element, e);
-               }
-       }
-
-       @Override
-       public Image getImage(Object element) {
-               try {
-                       if (element instanceof Row)
-                               return getRowImage((Row) element);
-                       else
-                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Repository exception when accessing " + element, e);
-               }
-       }
-
-       @Override
-       public String getToolTipText(Object element) {
-               try {
-                       if (element instanceof Row)
-                               return getRowToolTipText((Row) element);
-                       else
-                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Repository exception when accessing " + element, e);
-               }
-       }
-
-       @Override
-       public Font getFont(Object element) {
-               try {
-                       if (element instanceof Row)
-                               return getRowFont((Row) element);
-                       else
-                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Repository exception when accessing " + element, e);
-               }
-       }
-
-       @Override
-       public Color getBackground(Object element) {
-               try {
-                       if (element instanceof Row)
-                               return getRowBackground((Row) element);
-                       else
-                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Repository exception when accessing " + element, e);
-               }
-       }
-
-       @Override
-       public Color getForeground(Object element) {
-               try {
-                       if (element instanceof Row)
-                               return getRowForeground((Row) element);
-                       else
-                               throw new IllegalArgumentException("Unsupported element type " + element.getClass());
-               } catch (RepositoryException e) {
-                       throw new IllegalStateException("Repository exception when accessing " + element, e);
-               }
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/SimpleNodeContentProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/SimpleNodeContentProvider.java
deleted file mode 100644 (file)
index cb235d7..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.jcr.JcrUtils;
-
-/** Simple JCR node content provider taking a list of String as base path. */
-public class SimpleNodeContentProvider extends AbstractNodeContentProvider {
-       private static final long serialVersionUID = -8245193308831384269L;
-       private final List<String> basePaths;
-       private Boolean mkdirs = false;
-
-       public SimpleNodeContentProvider(Session session, String... basePaths) {
-               this(session, Arrays.asList(basePaths));
-       }
-
-       public SimpleNodeContentProvider(Session session, List<String> basePaths) {
-               super(session);
-               this.basePaths = basePaths;
-       }
-
-       @Override
-       protected Boolean isBasePath(String path) {
-               if (basePaths.contains(path))
-                       return true;
-               return super.isBasePath(path);
-       }
-
-       public Object[] getElements(Object inputElement) {
-               try {
-                       List<Node> baseNodes = new ArrayList<Node>();
-                       for (String basePath : basePaths)
-                               if (mkdirs && !getSession().itemExists(basePath))
-                                       baseNodes.add(JcrUtils.mkdirs(getSession(), basePath));
-                               else
-                                       baseNodes.add(getSession().getNode(basePath));
-                       return baseNodes.toArray();
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot get base nodes for " + basePaths,
-                                       e);
-               }
-       }
-
-       public List<String> getBasePaths() {
-               return basePaths;
-       }
-
-       public void setMkdirs(Boolean mkdirs) {
-               this.mkdirs = mkdirs;
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/VersionColumnLabelProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/VersionColumnLabelProvider.java
deleted file mode 100644 (file)
index 1ce3154..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.version.Version;
-
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-import org.eclipse.swt.graphics.Image;
-
-/** Simplifies writing JCR-based column label provider. */
-public class VersionColumnLabelProvider extends ColumnLabelProvider {
-       private static final long serialVersionUID = -6117690082313161159L;
-
-       protected String getVersionText(Version version) throws RepositoryException {
-               return super.getText(version);
-       }
-
-       protected String getVersionToolTipText(Version version) throws RepositoryException {
-               return super.getToolTipText(version);
-       }
-
-       protected Image getVersionImage(Version version) throws RepositoryException {
-               return super.getImage(version);
-       }
-
-       protected String getUserName(Version version) throws RepositoryException {
-               Node node = version.getFrozenNode();
-               if(node.hasProperty(Property.JCR_LAST_MODIFIED_BY))
-                       return node.getProperty(Property.JCR_LAST_MODIFIED_BY).getString();
-               if(node.hasProperty(Property.JCR_CREATED_BY))
-                       return node.getProperty(Property.JCR_CREATED_BY).getString();
-               return null;
-       }
-       
-//     protected String getActivityTitle(Version version) throws RepositoryException {
-//             Node activity = getActivity(version);
-//             if (activity == null)
-//                     return null;
-//             if (activity.hasProperty("jcr:activityTitle"))
-//                     return activity.getProperty("jcr:activityTitle").getString();
-//             else
-//                     return activity.getName();
-//     }
-//
-//     protected Node getActivity(Version version) throws RepositoryException {
-//             if (version.hasProperty(Property.JCR_ACTIVITY)) {
-//                     return version.getProperty(Property.JCR_ACTIVITY).getNode();
-//             } else
-//                     return null;
-//     }
-
-       @Override
-       public String getText(Object element) {
-               try {
-                       return getVersionText((Version) element);
-               } catch (RepositoryException e) {
-                       throw new RuntimeException("Runtime repository exception when accessing " + element, e);
-               }
-       }
-
-       @Override
-       public Image getImage(Object element) {
-               try {
-                       return getVersionImage((Version) element);
-               } catch (RepositoryException e) {
-                       throw new RuntimeException("Runtime repository exception when accessing " + element, e);
-               }
-       }
-
-       @Override
-       public String getToolTipText(Object element) {
-               try {
-                       return getVersionToolTipText((Version) element);
-               } catch (RepositoryException e) {
-                       throw new RuntimeException("Runtime repository exception when accessing " + element, e);
-               }
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/VersionHistoryContentProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/VersionHistoryContentProvider.java
deleted file mode 100644 (file)
index 32e5d30..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import javax.jcr.version.VersionHistory;
-
-import org.argeo.jcr.Jcr;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.Viewer;
-
-/** Content provider based on a {@link VersionHistory}. */
-public class VersionHistoryContentProvider implements IStructuredContentProvider {
-       private static final long serialVersionUID = -4921107883428887012L;
-
-       @Override
-       public void dispose() {
-       }
-
-       @Override
-       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-       }
-
-       @Override
-       public Object[] getElements(Object inputElement) {
-               VersionHistory versionHistory = (VersionHistory) inputElement;
-               return Jcr.getLinearVersions(versionHistory).toArray();
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/WrappedNode.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/WrappedNode.java
deleted file mode 100644 (file)
index 43df1fe..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.argeo.eclipse.ui.jcr;
-
-import javax.jcr.Node;
-
-/** Wrap a node (created from a {@link NodesWrapper}) */
-public class WrappedNode {
-       private final NodesWrapper parent;
-       private final Node node;
-
-       public WrappedNode(NodesWrapper parent, Node node) {
-               super();
-               this.parent = parent;
-               this.node = node;
-       }
-
-       public NodesWrapper getParent() {
-               return parent;
-       }
-
-       public Node getNode() {
-               return node;
-       }
-
-       public String toString() {
-               return "wrapped " + node;
-       }
-
-       @Override
-       public int hashCode() {
-               return node.hashCode();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (obj instanceof WrappedNode)
-                       return node.equals(((WrappedNode) obj).getNode());
-               else
-                       return false;
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/JcrColumnDefinition.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/JcrColumnDefinition.java
deleted file mode 100644 (file)
index c5dd733..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-package org.argeo.eclipse.ui.jcr.lists;
-
-import javax.jcr.Node;
-import javax.jcr.query.Row;
-
-import org.argeo.eclipse.ui.ColumnDefinition;
-
-/**
- * Utility object to manage column in various tables and extracts displaying
- * data from JCR
- */
-public class JcrColumnDefinition extends ColumnDefinition {
-       private final static int DEFAULT_COLUMN_SIZE = 120;
-
-       private String selectorName;
-       private String propertyName;
-       private int propertyType;
-       private int columnSize;
-
-       /**
-        * Use this kind of columns to configure a table that displays JCR
-        * {@link Row}
-        * 
-        * @param selectorName
-        * @param propertyName
-        * @param propertyType
-        * @param headerLabel
-        */
-       public JcrColumnDefinition(String selectorName, String propertyName,
-                       int propertyType, String headerLabel) {
-               super(new SimpleJcrRowLabelProvider(selectorName, propertyName),
-                               headerLabel);
-               this.selectorName = selectorName;
-               this.propertyName = propertyName;
-               this.propertyType = propertyType;
-               this.columnSize = DEFAULT_COLUMN_SIZE;
-       }
-
-       /**
-        * Use this kind of columns to configure a table that displays JCR
-        * {@link Row}
-        * 
-        * @param selectorName
-        * @param propertyName
-        * @param propertyType
-        * @param headerLabel
-        * @param columnSize
-        */
-       public JcrColumnDefinition(String selectorName, String propertyName,
-                       int propertyType, String headerLabel, int columnSize) {
-               super(new SimpleJcrRowLabelProvider(selectorName, propertyName),
-                               headerLabel, columnSize);
-               this.selectorName = selectorName;
-               this.propertyName = propertyName;
-               this.propertyType = propertyType;
-               this.columnSize = columnSize;
-       }
-
-       /**
-        * Use this kind of columns to configure a table that displays JCR
-        * {@link Node}
-        * 
-        * @param propertyName
-        * @param propertyType
-        * @param headerLabel
-        * @param columnSize
-        */
-       public JcrColumnDefinition(String propertyName, int propertyType,
-                       String headerLabel, int columnSize) {
-               super(new SimpleJcrNodeLabelProvider(propertyName), headerLabel,
-                               columnSize);
-               this.propertyName = propertyName;
-               this.propertyType = propertyType;
-               this.columnSize = columnSize;
-       }
-
-       public String getSelectorName() {
-               return selectorName;
-       }
-
-       public void setSelectorName(String selectorName) {
-               this.selectorName = selectorName;
-       }
-
-       public String getPropertyName() {
-               return propertyName;
-       }
-
-       public void setPropertyName(String propertyName) {
-               this.propertyName = propertyName;
-       }
-
-       public int getPropertyType() {
-               return propertyType;
-       }
-
-       public void setPropertyType(int propertyType) {
-               this.propertyType = propertyType;
-       }
-
-       public int getColumnSize() {
-               return columnSize;
-       }
-
-       public void setColumnSize(int columnSize) {
-               this.columnSize = columnSize;
-       }
-
-       public String getHeaderLabel() {
-               return super.getLabel();
-       }
-
-       public void setHeaderLabel(String headerLabel) {
-               super.setLabel(headerLabel);
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/NodeViewerComparator.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/NodeViewerComparator.java
deleted file mode 100644 (file)
index 341b3ab..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-package org.argeo.eclipse.ui.jcr.lists;
-
-import java.math.BigDecimal;
-import java.util.Calendar;
-
-import javax.jcr.Node;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-import javax.jcr.ValueFormatException;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.viewers.ViewerComparator;
-
-/**
- * Base comparator to enable ordering on Table or Tree viewer that display Jcr
- * Nodes.
- * 
- * Note that the following snippet must be added before setting the comparator
- * to the corresponding control: <code>
- * // IMPORTANT: initialize comparator before setting it
- * JcrColumnDefinition firstCol = colDefs.get(0);
- * comparator.setColumn(firstCol.getPropertyType(),
- * firstCol.getPropertyName());
- * viewer.setComparator(comparator); </code>
- */
-public class NodeViewerComparator extends ViewerComparator {
-       private static final long serialVersionUID = -7782916140737279027L;
-
-       protected String propertyName;
-
-       protected int propertyType;
-       public static final int ASCENDING = 0, DESCENDING = 1;
-       protected int direction = DESCENDING;
-
-       public NodeViewerComparator() {
-       }
-
-       /**
-        * e1 and e2 must both be Jcr nodes.
-        * 
-        * @param viewer
-        * @param e1
-        * @param e2
-        * @return
-        */
-       @Override
-       public int compare(Viewer viewer, Object e1, Object e2) {
-               int rc = 0;
-               long lc = 0;
-
-               try {
-                       Node n1 = (Node) e1;
-                       Node n2 = (Node) e2;
-
-                       Value v1 = null;
-                       Value v2 = null;
-                       if (n1.hasProperty(propertyName))
-                               v1 = n1.getProperty(propertyName).getValue();
-                       if (n2.hasProperty(propertyName))
-                               v2 = n2.getProperty(propertyName).getValue();
-
-                       if (v2 == null && v1 == null)
-                               return 0;
-                       else if (v2 == null)
-                               return -1;
-                       else if (v1 == null)
-                               return 1;
-
-                       switch (propertyType) {
-                       case PropertyType.STRING:
-                               rc = v1.getString().compareTo(v2.getString());
-                               break;
-                       case PropertyType.BOOLEAN:
-                               boolean b1 = v1.getBoolean();
-                               boolean b2 = v2.getBoolean();
-                               if (b1 == b2)
-                                       rc = 0;
-                               else
-                                       // we assume true is greater than false
-                                       rc = b1 ? 1 : -1;
-                               break;
-                       case PropertyType.DATE:
-                               Calendar c1 = v1.getDate();
-                               Calendar c2 = v2.getDate();
-                               if (c1 == null || c2 == null)
-                                       // log.trace("undefined date");
-                                       ;
-                               lc = c1.getTimeInMillis() - c2.getTimeInMillis();
-                               if (lc < Integer.MIN_VALUE)
-                                       rc = -1;
-                               else if (lc > Integer.MAX_VALUE)
-                                       rc = 1;
-                               else
-                                       rc = (int) lc;
-                               break;
-                       case PropertyType.LONG:
-                               long l1;
-                               long l2;
-                               // TODO Sometimes an empty string is set instead of a long
-                               try {
-                                       l1 = v1.getLong();
-                               } catch (ValueFormatException ve) {
-                                       l1 = 0;
-                               }
-                               try {
-                                       l2 = v2.getLong();
-                               } catch (ValueFormatException ve) {
-                                       l2 = 0;
-                               }
-
-                               lc = l1 - l2;
-                               if (lc < Integer.MIN_VALUE)
-                                       rc = -1;
-                               else if (lc > Integer.MAX_VALUE)
-                                       rc = 1;
-                               else
-                                       rc = (int) lc;
-                               break;
-                       case PropertyType.DECIMAL:
-                               BigDecimal bd1 = v1.getDecimal();
-                               BigDecimal bd2 = v2.getDecimal();
-                               rc = bd1.compareTo(bd2);
-                               break;
-                       case PropertyType.DOUBLE:
-                               Double d1 = v1.getDouble();
-                               Double d2 = v2.getDouble();
-                               rc = d1.compareTo(d2);
-                               break;
-                       default:
-                               throw new EclipseUiException(
-                                               "Unimplemented comparaison for PropertyType "
-                                                               + propertyType);
-                       }
-                       // If descending order, flip the direction
-                       if (direction == DESCENDING) {
-                               rc = -rc;
-                       }
-
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Unexpected error "
-                                       + "while comparing nodes", re);
-               }
-               return rc;
-       }
-
-       /**
-        * @param propertyType
-        *            Corresponding JCR type
-        * @param propertyName
-        *            name of the property to use.
-        */
-       public void setColumn(int propertyType, String propertyName) {
-               if (this.propertyName != null && this.propertyName.equals(propertyName)) {
-                       // Same column as last sort; toggle the direction
-                       direction = 1 - direction;
-               } else {
-                       // New column; do an ascending sort
-                       this.propertyType = propertyType;
-                       this.propertyName = propertyName;
-                       direction = ASCENDING;
-               }
-       }
-
-       // Getters and setters
-       protected String getPropertyName() {
-               return propertyName;
-       }
-
-       protected void setPropertyName(String propertyName) {
-               this.propertyName = propertyName;
-       }
-
-       protected int getPropertyType() {
-               return propertyType;
-       }
-
-       protected void setPropertyType(int propertyType) {
-               this.propertyType = propertyType;
-       }
-
-       protected int getDirection() {
-               return direction;
-       }
-
-       protected void setDirection(int direction) {
-               this.direction = direction;
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/RowViewerComparator.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/RowViewerComparator.java
deleted file mode 100644 (file)
index 455fb0d..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.argeo.eclipse.ui.jcr.lists;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.query.Row;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.jface.viewers.Viewer;
-
-/**
- * Base comparator to enable ordering on Table or Tree viewer that display Jcr
- * rows
- */
-public class RowViewerComparator extends NodeViewerComparator {
-       private static final long serialVersionUID = 7020939505172625113L;
-       protected String selectorName;
-
-       public RowViewerComparator() {
-       }
-
-       /**
-        * e1 and e2 must both be Jcr rows.
-        * 
-        * @param viewer
-        * @param e1
-        * @param e2
-        * @return
-        */
-       @Override
-       public int compare(Viewer viewer, Object e1, Object e2) {
-               try {
-                       Node n1 = ((Row) e1).getNode(selectorName);
-                       Node n2 = ((Row) e2).getNode(selectorName);
-                       return super.compare(viewer, n1, n2);
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Unexpected error "
-                                       + "while comparing nodes", re);
-               }
-       }
-
-       /**
-        * @param propertyType
-        *            Corresponding JCR type
-        * @param propertyName
-        *            name of the property to use.
-        */
-       public void setColumn(int propertyType, String selectorName,
-                       String propertyName) {
-               if (this.selectorName != null && getPropertyName() != null
-                               && this.selectorName.equals(selectorName)
-                               && this.getPropertyName().equals(propertyName)) {
-                       // Same column as last sort; toggle the direction
-                       setDirection(1 - getDirection());
-               } else {
-                       // New column; do a descending sort
-                       setPropertyType(propertyType);
-                       setPropertyName(propertyName);
-                       this.selectorName = selectorName;
-                       setDirection(NodeViewerComparator.ASCENDING);
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/SimpleJcrNodeLabelProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/SimpleJcrNodeLabelProvider.java
deleted file mode 100644 (file)
index aa2e337..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-package org.argeo.eclipse.ui.jcr.lists;
-
-import java.text.DateFormat;
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.text.SimpleDateFormat;
-
-import javax.jcr.Node;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
-
-/** Base implementation of a label provider for controls that display JCR Nodes */
-public class SimpleJcrNodeLabelProvider extends ColumnLabelProvider {
-       private static final long serialVersionUID = -5215787695436221993L;
-
-       private final static String DEFAULT_DATE_FORMAT = "EEE, dd MMM yyyy";
-       private final static String DEFAULT_NUMBER_FORMAT = "#,##0.0";
-
-       private DateFormat dateFormat;
-       private NumberFormat numberFormat;
-
-       final private String propertyName;
-
-       /**
-        * Default Label provider for a given property of a node. Using default
-        * pattern for date and number formating
-        */
-       public SimpleJcrNodeLabelProvider(String propertyName) {
-               this.propertyName = propertyName;
-               dateFormat = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
-               numberFormat = DecimalFormat.getInstance();
-               ((DecimalFormat) numberFormat).applyPattern(DEFAULT_NUMBER_FORMAT);
-       }
-
-       /**
-        * Label provider for a given property of a node optionally precising date
-        * and/or number format patterns
-        */
-       public SimpleJcrNodeLabelProvider(String propertyName,
-                       String dateFormatPattern, String numberFormatPattern) {
-               this.propertyName = propertyName;
-               dateFormat = new SimpleDateFormat(
-                               dateFormatPattern == null ? DEFAULT_DATE_FORMAT
-                                               : dateFormatPattern);
-               numberFormat = DecimalFormat.getInstance();
-               ((DecimalFormat) numberFormat)
-                               .applyPattern(numberFormatPattern == null ? DEFAULT_NUMBER_FORMAT
-                                               : numberFormatPattern);
-       }
-
-       @Override
-       public String getText(Object element) {
-               try {
-                       Node currNode = (Node) element;
-
-                       if (currNode.hasProperty(propertyName)) {
-                               if (currNode.getProperty(propertyName).isMultiple()) {
-                                       StringBuilder builder = new StringBuilder();
-                                       for (Value value : currNode.getProperty(propertyName)
-                                                       .getValues()) {
-                                               String currStr = getSingleValueAsString(value);
-                                               if (notEmptyString(currStr))
-                                                       builder.append(currStr).append("; ");
-                                       }
-                                       if (builder.length() > 0)
-                                               builder.deleteCharAt(builder.length() - 2);
-
-                                       return builder.toString();
-                               } else
-                                       return getSingleValueAsString(currNode.getProperty(
-                                                       propertyName).getValue());
-                       } else
-                               return "";
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Unable to get text from row", re);
-               }
-       }
-
-       private String getSingleValueAsString(Value value)
-                       throws RepositoryException {
-               switch (value.getType()) {
-               case PropertyType.STRING:
-                       return value.getString();
-               case PropertyType.BOOLEAN:
-                       return "" + value.getBoolean();
-               case PropertyType.DATE:
-                       return dateFormat.format(value.getDate().getTime());
-               case PropertyType.LONG:
-                       return "" + value.getLong();
-               case PropertyType.DECIMAL:
-                       return numberFormat.format(value.getDecimal());
-               case PropertyType.DOUBLE:
-                       return numberFormat.format(value.getDouble());
-               case PropertyType.NAME:
-                       return value.getString();
-               default:
-                       throw new EclipseUiException("Unimplemented label provider "
-                                       + "for property type " + value.getType()
-                                       + " while getting property " + propertyName + " - value: "
-                                       + value.getString());
-
-               }
-       }
-
-       private boolean notEmptyString(String string) {
-               return string != null && !"".equals(string.trim());
-       }
-
-       public void setDateFormat(String dateFormatPattern) {
-               dateFormat = new SimpleDateFormat(dateFormatPattern);
-       }
-
-       public void setNumberFormat(String numberFormatPattern) {
-               ((DecimalFormat) numberFormat).applyPattern(numberFormatPattern);
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/SimpleJcrRowLabelProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/SimpleJcrRowLabelProvider.java
deleted file mode 100644 (file)
index 5d421f6..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.argeo.eclipse.ui.jcr.lists;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.query.Row;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-
-/**
- * Base implementation of a label provider for widgets that display JCR Rows.
- */
-public class SimpleJcrRowLabelProvider extends SimpleJcrNodeLabelProvider {
-       private static final long serialVersionUID = -3414654948197181740L;
-
-       final private String selectorName;
-
-       /**
-        * Default Label provider for a given property of a row. Using default
-        * pattern for date and number formating
-        */
-       public SimpleJcrRowLabelProvider(String selectorName, String propertyName) {
-               super(propertyName);
-               this.selectorName = selectorName;
-       }
-
-       /**
-        * Label provider for a given property of a node optionally precising date
-        * and/or number format patterns
-        */
-       public SimpleJcrRowLabelProvider(String selectorName, String propertyName,
-                       String dateFormatPattern, String numberFormatPattern) {
-               super(propertyName, dateFormatPattern, numberFormatPattern);
-               this.selectorName = selectorName;
-       }
-
-       @Override
-       public String getText(Object element) {
-               try {
-                       Row currRow = (Row) element;
-                       Node currNode = currRow.getNode(selectorName);
-                       return super.getText(currNode);
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Unable to get Node " + selectorName
-                                       + " from row " + element, re);
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/package-info.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/lists/package-info.java
deleted file mode 100644 (file)
index 3678aab..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Generic SWT/JFace JCR utilities for lists. */
-package org.argeo.eclipse.ui.jcr.lists;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/package-info.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/package-info.java
deleted file mode 100644 (file)
index 19e3cc3..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Generic SWT/JFace JCR utilities. */
-package org.argeo.eclipse.ui.jcr;
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/JcrFileProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/JcrFileProvider.java
deleted file mode 100644 (file)
index c82e666..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-package org.argeo.eclipse.ui.jcr.util;
-
-import java.io.InputStream;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.FileProvider;
-
-/**
- * Implements a FileProvider for UI purposes. Note that it might not be very
- * reliable as long as we have not fixed login and multi repository issues that
- * will be addressed in the next version.
- * 
- * NOTE: id used here is the real id of the JCR Node, not the JCR Path
- * 
- * Relies on common approach for JCR file handling implementation.
- * 
- */
-@SuppressWarnings("deprecation")
-public class JcrFileProvider implements FileProvider {
-
-       // private Object[] rootNodes;
-       private Node refNode;
-
-       /**
-        * Must be set in order for the provider to be able to get current session
-        * and thus have the ability to get the file node corresponding to a given
-        * file ID
-        * 
-        * @param refNode
-        */
-       public void setReferenceNode(Node refNode) {
-               // FIXME : this introduces some concurrency ISSUES.
-               this.refNode = refNode;
-       }
-
-       public byte[] getByteArrayFileFromId(String fileId) {
-               InputStream fis = null;
-               byte[] ba = null;
-               Node child = getFileNodeFromId(fileId);
-               try {
-                       fis = (InputStream) child.getProperty(Property.JCR_DATA).getBinary().getStream();
-                       ba = IOUtils.toByteArray(fis);
-
-               } catch (Exception e) {
-                       throw new EclipseUiException("Stream error while opening file", e);
-               } finally {
-                       IOUtils.closeQuietly(fis);
-               }
-               return ba;
-       }
-
-       public InputStream getInputStreamFromFileId(String fileId) {
-               try {
-                       InputStream fis = null;
-
-                       Node child = getFileNodeFromId(fileId);
-                       fis = (InputStream) child.getProperty(Property.JCR_DATA).getBinary().getStream();
-                       return fis;
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Cannot get stream from file node for Id " + fileId, re);
-               }
-       }
-
-       /**
-        * Throws an exception if the node is not found in the current repository (a
-        * bit like a FileNotFoundException)
-        * 
-        * @param fileId
-        * @return Returns the child node of the nt:file node. It is the child node
-        *         that have the jcr:data property where actual file is stored.
-        *         never null
-        */
-       private Node getFileNodeFromId(String fileId) {
-               try {
-                       Node result = refNode.getSession().getNodeByIdentifier(fileId);
-
-                       // rootNodes: for (int j = 0; j < rootNodes.length; j++) {
-                       // // in case we have a classic JCR Node
-                       // if (rootNodes[j] instanceof Node) {
-                       // Node curNode = (Node) rootNodes[j];
-                       // if (result != null)
-                       // break rootNodes;
-                       // } // Case of a repository Node
-                       // else if (rootNodes[j] instanceof RepositoryNode) {
-                       // Object[] nodes = ((RepositoryNode) rootNodes[j])
-                       // .getChildren();
-                       // for (int i = 0; i < nodes.length; i++) {
-                       // Node node = (Node) nodes[i];
-                       // result = node.getSession().getNodeByIdentifier(fileId);
-                       // if (result != null)
-                       // break rootNodes;
-                       // }
-                       // }
-                       // }
-
-                       // Sanity checks
-                       if (result == null)
-                               throw new EclipseUiException("File node not found for ID" + fileId);
-
-                       Node child = null;
-
-                       boolean isValid = true;
-                       if (!result.isNodeType(NodeType.NT_FILE))
-                               // useless: mandatory child node
-                               // || !result.hasNode(Property.JCR_CONTENT))
-                               isValid = false;
-                       else {
-                               child = result.getNode(Property.JCR_CONTENT);
-                               if (!(child.isNodeType(NodeType.NT_RESOURCE) || child.hasProperty(Property.JCR_DATA)))
-                                       isValid = false;
-                       }
-
-                       if (!isValid)
-                               throw new EclipseUiException("ERROR: In the current implemented model, '" + NodeType.NT_FILE
-                                               + "' file node must have a child node named jcr:content "
-                                               + "that has a BINARY Property named jcr:data " + "where the actual data is stored");
-                       return child;
-
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Erreur while getting file node of ID " + fileId, re);
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/JcrItemsComparator.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/JcrItemsComparator.java
deleted file mode 100644 (file)
index fb12399..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.argeo.eclipse.ui.jcr.util;
-
-import java.util.Comparator;
-
-import javax.jcr.Item;
-import javax.jcr.RepositoryException;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-
-/** Compares two JCR items (node or properties) based on their names. */
-public class JcrItemsComparator implements Comparator<Item> {
-       public int compare(Item o1, Item o2) {
-               try {
-                       // TODO: put folder before files
-                       return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase());
-               } catch (RepositoryException e) {
-                       throw new EclipseUiException("Cannot compare " + o1 + " and " + o2, e);
-               }
-       }
-
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/NodeViewerComparer.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/NodeViewerComparer.java
deleted file mode 100644 (file)
index 54b795f..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.argeo.eclipse.ui.jcr.util;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.eclipse.jface.viewers.IElementComparer;
-
-/** Compare JCR nodes based on their JCR identifiers, for use in JFace viewers. */
-public class NodeViewerComparer implements IElementComparer {
-
-       // force comparison on Node IDs only.
-       public boolean equals(Object elementA, Object elementB) {
-               if (!(elementA instanceof Node) || !(elementB instanceof Node)) {
-                       return elementA == null ? elementB == null : elementA
-                                       .equals(elementB);
-               } else {
-
-                       boolean result = false;
-                       try {
-                               String idA = ((Node) elementA).getIdentifier();
-                               String idB = ((Node) elementB).getIdentifier();
-                               result = idA == null ? idB == null : idA.equals(idB);
-                       } catch (RepositoryException re) {
-                               throw new EclipseUiException("cannot compare nodes", re);
-                       }
-
-                       return result;
-               }
-       }
-
-       public int hashCode(Object element) {
-               // TODO enhanced this method.
-               return element.getClass().toString().hashCode();
-       }
-}
\ No newline at end of file
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/SingleSessionFileProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/SingleSessionFileProvider.java
deleted file mode 100644 (file)
index 291d579..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.argeo.eclipse.ui.jcr.util;
-
-import java.io.InputStream;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.eclipse.ui.EclipseUiException;
-import org.argeo.eclipse.ui.FileProvider;
-
-/**
- * Implements a FileProvider for UI purposes. Unlike the
- * <code> JcrFileProvider </code>, it relies on a single session and manages
- * nodes with path only.
- * 
- * Note that considered id is the JCR path
- * 
- * Relies on common approach for JCR file handling implementation.
- */
-@SuppressWarnings("deprecation")
-public class SingleSessionFileProvider implements FileProvider {
-
-       private Session session;
-
-       public SingleSessionFileProvider(Session session) {
-               this.session = session;
-       }
-
-       public byte[] getByteArrayFileFromId(String fileId) {
-               InputStream fis = null;
-               byte[] ba = null;
-               Node child = getFileNodeFromId(fileId);
-               try {
-                       fis = (InputStream) child.getProperty(Property.JCR_DATA)
-                                       .getBinary().getStream();
-                       ba = IOUtils.toByteArray(fis);
-
-               } catch (Exception e) {
-                       throw new EclipseUiException("Stream error while opening file", e);
-               } finally {
-                       IOUtils.closeQuietly(fis);
-               }
-               return ba;
-       }
-
-       public InputStream getInputStreamFromFileId(String fileId) {
-               try {
-                       InputStream fis = null;
-
-                       Node child = getFileNodeFromId(fileId);
-                       fis = (InputStream) child.getProperty(Property.JCR_DATA)
-                                       .getBinary().getStream();
-                       return fis;
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Cannot get stream from file node for Id "
-                                       + fileId, re);
-               }
-       }
-
-       /**
-        * 
-        * @param fileId
-        * @return Returns the child node of the nt:file node. It is the child node
-        *         that have the jcr:data property where actual file is stored.
-        *         never null
-        */
-       private Node getFileNodeFromId(String fileId) {
-               try {
-                       Node result = null;
-                       result = session.getNode(fileId);
-
-                       // Sanity checks
-                       if (result == null)
-                               throw new EclipseUiException("File node not found for ID" + fileId);
-
-                       // Ensure that the node have the correct type.
-                       if (!result.isNodeType(NodeType.NT_FILE))
-                               throw new EclipseUiException(
-                                               "Cannot open file children Node that are not of "
-                                                               + NodeType.NT_RESOURCE + " type.");
-
-                       Node child = result.getNodes().nextNode();
-                       if (child == null || !child.isNodeType(NodeType.NT_RESOURCE))
-                               throw new EclipseUiException(
-                                               "ERROR: IN the current implemented model, "
-                                                               + NodeType.NT_FILE
-                                                               + "  file node must have one and only one child of the nt:ressource, where actual data is stored");
-                       return child;
-               } catch (RepositoryException re) {
-                       throw new EclipseUiException("Erreur while getting file node of ID "
-                                       + fileId, re);
-               }
-       }
-}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/package-info.java b/jcr/org.argeo.cms.ui/src/org/argeo/eclipse/ui/jcr/util/package-info.java
deleted file mode 100644 (file)
index 016348c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Generic SWT/JFace JCR helpers. */
-package org.argeo.eclipse.ui.jcr.util;
\ No newline at end of file
diff --git a/org.argeo.cms.ux/src/org/argeo/cms/ux/AbstractImageManager.java b/org.argeo.cms.ux/src/org/argeo/cms/ux/AbstractImageManager.java
new file mode 100644 (file)
index 0000000..41c905e
--- /dev/null
@@ -0,0 +1,62 @@
+package org.argeo.cms.ux;
+
+import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.api.cms.ux.CmsImageManager;
+
+/** Manages only public images so far. */
+public abstract class AbstractImageManager<V, M> implements CmsImageManager<V, M> {
+       public final static String NO_IMAGE = "icons/noPic-square-640px.png";
+       public final static Cms2DSize NO_IMAGE_SIZE = new Cms2DSize(320, 320);
+       public final static Float NO_IMAGE_RATIO = 1f;
+
+       protected Cms2DSize resizeTo(Cms2DSize orig, Cms2DSize constraints) {
+               if (constraints.getWidth() != 0 && constraints.getHeight() != 0) {
+                       return constraints;
+               } else if (constraints.getWidth() == 0 && constraints.getHeight() == 0) {
+                       return orig;
+               } else if (constraints.getHeight() == 0) {// force width
+                       return new Cms2DSize(constraints.getWidth(),
+                                       scale(orig.getHeight(), orig.getWidth(), constraints.getWidth()));
+               } else if (constraints.getWidth() == 0) {// force height
+                       return new Cms2DSize(scale(orig.getWidth(), orig.getHeight(), constraints.getHeight()),
+                                       constraints.getHeight());
+               }
+               throw new IllegalArgumentException("Cannot resize " + orig + " to " + constraints);
+       }
+
+       protected int scale(int origDimension, int otherDimension, int otherConstraint) {
+               return Math.round(origDimension * divide(otherConstraint, otherDimension));
+       }
+
+       protected float divide(int a, int b) {
+               return ((float) a) / ((float) b);
+       }
+
+       /** @return null if not available */
+       @Override
+       public String getImageTag(M node) {
+               return getImageTag(node, getImageSize(node));
+       }
+
+       protected String getImageTag(M node, Cms2DSize size) {
+               StringBuilder buf = getImageTagBuilder(node, size);
+               if (buf == null)
+                       return null;
+               return buf.append("/>").toString();
+       }
+
+       /** @return null if not available */
+       @Override
+       public StringBuilder getImageTagBuilder(M node, Cms2DSize size) {
+               return getImageTagBuilder(node, Integer.toString(size.getWidth()), Integer.toString(size.getHeight()));
+       }
+
+       /** @return null if not available */
+       protected StringBuilder getImageTagBuilder(M node, String width, String height) {
+               String url = getImageUrl(node);
+               if (url == null)
+                       return null;
+               return CmsUxUtils.imgBuilder(url, width, height);
+       }
+
+}
index d6fd221a456a4d1ee41dfd3443d7e786192f148e..916cc74f2feb4c8bef5f9d3cb2be460e3f549d17 100644 (file)
@@ -3,6 +3,7 @@ package org.argeo.cms.ux;
 import org.argeo.api.acr.Content;
 import org.argeo.api.acr.ContentRepository;
 import org.argeo.api.acr.ContentSession;
+import org.argeo.api.cms.ux.Cms2DSize;
 import org.argeo.api.cms.ux.CmsView;
 import org.argeo.util.CurrentSubject;
 
@@ -19,4 +20,17 @@ public class CmsUxUtils {
        private CmsUxUtils() {
 
        }
+
+       public static StringBuilder imgBuilder(String src, String width, String height) {
+               return new StringBuilder(64).append("<img width='").append(width).append("' height='").append(height)
+                               .append("' src='").append(src).append("'");
+       }
+
+       public static String img(String src, String width, String height) {
+               return imgBuilder(src, width, height).append("/>").toString();
+       }
+
+       public static String img(String src, Cms2DSize size) {
+               return img(src, Integer.toString(size.getWidth()), Integer.toString(size.getHeight()));
+       }
 }
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/AbstractSwtImageManager.java b/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/AbstractSwtImageManager.java
new file mode 100644 (file)
index 0000000..00a51ef
--- /dev/null
@@ -0,0 +1,77 @@
+package org.argeo.cms.swt;
+
+import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.cms.ux.AbstractImageManager;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+/** Manages only public images so far. */
+public abstract class AbstractSwtImageManager<M> extends AbstractImageManager<Control, M> {
+       protected abstract Image getSwtImage(M node);
+
+       protected abstract String noImg(Cms2DSize size);
+
+       public Boolean load(M node, Control control, Cms2DSize preferredSize) {
+               Cms2DSize imageSize = getImageSize(node);
+               Cms2DSize size;
+               String imgTag = null;
+               if (preferredSize == null || imageSize.getWidth() == 0 || imageSize.getHeight() == 0
+                               || (preferredSize.getWidth() == 0 && preferredSize.getHeight() == 0)) {
+                       if (imageSize.getWidth() != 0 && imageSize.getHeight() != 0) {
+                               // actual image size if completely known
+                               size = imageSize;
+                       } else {
+                               // no image if not completely known
+                               size = resizeTo(NO_IMAGE_SIZE, preferredSize != null ? preferredSize : imageSize);
+                               imgTag = noImg(size);
+                       }
+
+               } else if (preferredSize.getWidth() != 0 && preferredSize.getHeight() != 0) {
+                       // given size if completely provided
+                       size = preferredSize;
+               } else {
+                       // at this stage :
+                       // image is completely known
+                       assert imageSize.getWidth() != 0 && imageSize.getHeight() != 0;
+                       // one and only one of the dimension as been specified
+                       assert preferredSize.getWidth() == 0 || preferredSize.getHeight() == 0;
+                       size = resizeTo(imageSize, preferredSize);
+               }
+
+               boolean loaded = false;
+               if (control == null)
+                       return loaded;
+
+               if (control instanceof Label) {
+                       if (imgTag == null) {
+                               // IMAGE RETRIEVED HERE
+                               imgTag = getImageTag(node, size);
+                               //
+                               if (imgTag == null)
+                                       imgTag = noImg(size);
+                               else
+                                       loaded = true;
+                       }
+
+                       Label lbl = (Label) control;
+                       lbl.setText(imgTag);
+                       // lbl.setSize(size);
+//             } else if (control instanceof FileUpload) {
+//                     FileUpload lbl = (FileUpload) control;
+//                     lbl.setImage(CmsUiUtils.noImage(size));
+//                     lbl.setSize(new Point(size.getWidth(), size.getHeight()));
+//                     return loaded;
+               } else
+                       loaded = false;
+
+               return loaded;
+       }
+
+       public Cms2DSize getImageSize(M node) {
+               // TODO optimise
+               Image image = getSwtImage(node);
+               return new Cms2DSize(image.getBounds().width, image.getBounds().height);
+       }
+
+}
diff --git a/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/AcrSwtImageManager.java b/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/AcrSwtImageManager.java
new file mode 100644 (file)
index 0000000..5e83454
--- /dev/null
@@ -0,0 +1,37 @@
+package org.argeo.cms.swt.acr;
+
+import java.io.InputStream;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.cms.ux.Cms2DSize;
+import org.argeo.cms.swt.AbstractSwtImageManager;
+import org.eclipse.swt.graphics.Image;
+
+public class AcrSwtImageManager extends AbstractSwtImageManager<Content> {
+
+       @Override
+       public String getImageUrl(Content node) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       public String uploadImage(Content context, Content uploadFolder, String fileName, InputStream in,
+                       String contentType) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       protected Image getSwtImage(Content node) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       protected String noImg(Cms2DSize size) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+}
index 5bbe4bc4b721199acd5fdc50adac322d0ddaf640..29ce1708ab689b2ddcc8ab3684aec8a4463ac990 100644 (file)
@@ -1,7 +1,9 @@
 Bundle-ActivationPolicy: lazy
 Service-Component: OSGI-INF/cms-admin-rap.xml
 
-Import-Package: org.eclipse.swt,\
+Import-Package: \
+org.argeo.api.acr, \
+org.eclipse.swt,\
 org.eclipse.swt.graphics,\
 org.eclipse.e4.ui.workbench,\
 org.eclipse.rap.rwt.client,\
index 471cdeca546f6a809107395df345d11b5e948bc1..cdd4899289e59d3ce83751eaff39402a8ed115c1 100644 (file)
@@ -15,9 +15,9 @@ import org.argeo.api.cms.ux.UxContext;
 import org.argeo.cms.auth.CurrentUser;
 import org.argeo.cms.swt.CmsSwtUtils;
 import org.argeo.cms.swt.SimpleSwtUxContext;
+import org.argeo.cms.swt.acr.AcrSwtImageManager;
 import org.argeo.cms.swt.auth.CmsLoginShell;
 import org.argeo.cms.swt.dialogs.CmsFeedback;
-import org.argeo.cms.ui.util.SimpleImageManager;
 import org.eclipse.e4.core.services.events.IEventBroker;
 import org.eclipse.e4.ui.workbench.UIEvents;
 import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate;
@@ -82,7 +82,7 @@ public class CmsLoginLifecycle implements CmsView {
                if (CurrentUser.getUsername(getSubject()) == null)
                        return false;
                uxContext = new SimpleSwtUxContext();
-               imageManager = new SimpleImageManager();
+               imageManager = (CmsImageManager) new AcrSwtImageManager();
 
                eventBroker.subscribe(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE, new EventHandler() {
                        @Override
index db2ac0bebcbc09c4b47c67e84a9d471b43ba5fe1..81178ebd3fb461a4163c4754a82f55b5a8c55669 100644 (file)
@@ -2,8 +2,6 @@ Import-Package:\
 org.argeo.api.acr,\
 org.eclipse.swt,\
 org.argeo.eclipse.ui,\
-javax.jcr.nodetype,\
-javax.jcr.security,\
 org.eclipse.swt.graphics,\
 javax.servlet.*;version="[3,5)",\
 *
diff --git a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/AppUi.java b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/AppUi.java
deleted file mode 100644 (file)
index 01ebb23..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-package org.argeo.cms.ui.script;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.script.Invocable;
-import javax.script.ScriptException;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.Selected;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.util.CmsPane;
-import org.argeo.cms.web.SimpleErgonomics;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.EntryPoint;
-import org.eclipse.rap.rwt.application.EntryPointFactory;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.osgi.framework.BundleContext;
-
-public class AppUi implements CmsUiProvider, Branding {
-       private final CmsScriptApp app;
-
-       private CmsUiProvider ui;
-       private String createUi;
-       private Object impl;
-       private String script;
-       // private Branding branding = new Branding();
-
-       private EntryPointFactory factory;
-
-       // Branding
-       private String themeId;
-       private String additionalHeaders;
-       private String bodyHtml;
-       private String pageTitle;
-       private String pageOverflow;
-       private String favicon;
-
-       public AppUi(CmsScriptApp app) {
-               this.app = app;
-       }
-
-       public AppUi(CmsScriptApp app, String scriptPath) {
-               this.app = app;
-               this.ui = new ScriptUi((BundleContext) app.getScriptEngine().get(CmsScriptRwtApplication.BC),
-                               app.getScriptEngine(), scriptPath);
-       }
-
-       public AppUi(CmsScriptApp app, CmsUiProvider uiProvider) {
-               this.app = app;
-               this.ui = uiProvider;
-       }
-
-       public AppUi(CmsScriptApp app, EntryPointFactory factory) {
-               this.app = app;
-               this.factory = factory;
-       }
-
-       public void apply(Repository repository, Application application, Branding appBranding, String path) {
-               Map<String, String> factoryProperties = new HashMap<>();
-               if (appBranding != null)
-                       appBranding.applyBranding(factoryProperties);
-               applyBranding(factoryProperties);
-               if (factory != null) {
-                       application.addEntryPoint("/" + path, factory, factoryProperties);
-               } else {
-                       EntryPointFactory entryPointFactory = new EntryPointFactory() {
-                               @Override
-                               public EntryPoint create() {
-                                       SimpleErgonomics ergonomics = new SimpleErgonomics(repository, CmsConstants.SYS_WORKSPACE,
-                                                       "/home/root/argeo:keyring", AppUi.this, factoryProperties);
-//                                     CmsUiProvider header = app.getHeader();
-//                                     if (header != null)
-//                                             ergonomics.setHeader(header);
-                                       app.applySides(ergonomics);
-                                       Integer headerHeight = app.getHeaderHeight();
-                                       if (headerHeight != null)
-                                               ergonomics.setHeaderHeight(headerHeight);
-                                       return ergonomics;
-                               }
-                       };
-                       application.addEntryPoint("/" + path, entryPointFactory, factoryProperties);
-               }
-       }
-
-       public void setUi(CmsUiProvider uiProvider) {
-               this.ui = uiProvider;
-       }
-
-       public void applyBranding(Map<String, String> properties) {
-               if (themeId != null)
-                       properties.put(WebClient.THEME_ID, themeId);
-               if (additionalHeaders != null)
-                       properties.put(WebClient.HEAD_HTML, additionalHeaders);
-               if (bodyHtml != null)
-                       properties.put(WebClient.BODY_HTML, bodyHtml);
-               if (pageTitle != null)
-                       properties.put(WebClient.PAGE_TITLE, pageTitle);
-               if (pageOverflow != null)
-                       properties.put(WebClient.PAGE_OVERFLOW, pageOverflow);
-               if (favicon != null)
-                       properties.put(WebClient.FAVICON, favicon);
-       }
-
-       // public Branding getBranding() {
-       // return branding;
-       // }
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               CmsPane cmsPane = new CmsPane(parent, SWT.NONE);
-
-               if (false) {
-                       // QA
-                       CmsSwtUtils.style(cmsPane.getQaArea(), "qa");
-                       Button reload = new Button(cmsPane.getQaArea(), SWT.FLAT);
-                       CmsSwtUtils.style(reload, "qa");
-                       reload.setText("Reload");
-                       reload.addSelectionListener(new Selected() {
-                               private static final long serialVersionUID = 1L;
-
-                               @Override
-                               public void widgetSelected(SelectionEvent e) {
-                                       new Thread() {
-                                               @Override
-                                               public void run() {
-                                                       app.reload();
-                                               }
-                                       }.start();
-                                       RWT.getClient().getService(JavaScriptExecutor.class)
-                                                       .execute("setTimeout('location.reload()',1000)");
-                               }
-                       });
-
-                       // Support
-                       CmsSwtUtils.style(cmsPane.getSupportArea(), "support");
-                       Label msg = new Label(cmsPane.getSupportArea(), SWT.NONE);
-                       CmsSwtUtils.style(msg, "support");
-                       msg.setText("UNSUPPORTED DEVELOPMENT VERSION");
-               }
-
-               if (ui != null) {
-                       ui.createUi(cmsPane.getMainArea(), context);
-               }
-               if (createUi != null) {
-                       Invocable invocable = (Invocable) app.getScriptEngine();
-                       try {
-                               invocable.invokeFunction(createUi, cmsPane.getMainArea(), context);
-
-                       } catch (NoSuchMethodException e) {
-                               // TODO Auto-generated catch block
-                               e.printStackTrace();
-                       } catch (ScriptException e) {
-                               // TODO Auto-generated catch block
-                               e.printStackTrace();
-                       }
-               }
-               if (impl != null) {
-                       Invocable invocable = (Invocable) app.getScriptEngine();
-                       try {
-                               invocable.invokeMethod(impl, "createUi", cmsPane.getMainArea(), context);
-
-                       } catch (NoSuchMethodException e) {
-                               // TODO Auto-generated catch block
-                               e.printStackTrace();
-                       } catch (ScriptException e) {
-                               // TODO Auto-generated catch block
-                               e.printStackTrace();
-                       }
-               }
-
-               // Invocable invocable = (Invocable) app.getScriptEngine();
-               // try {
-               // invocable.invokeMethod(AppUi.this, "initUi", parent, context);
-               //
-               // } catch (NoSuchMethodException e) {
-               // // TODO Auto-generated catch block
-               // e.printStackTrace();
-               // } catch (ScriptException e) {
-               // // TODO Auto-generated catch block
-               // e.printStackTrace();
-               // }
-
-               return null;
-       }
-
-       public void setCreateUi(String createUi) {
-               this.createUi = createUi;
-       }
-
-       public void setImpl(Object impl) {
-               this.impl = impl;
-       }
-
-       public Object getImpl() {
-               return impl;
-       }
-
-       public String getScript() {
-               return script;
-       }
-
-       public void setScript(String script) {
-               this.script = script;
-       }
-
-       // Branding
-       public String getThemeId() {
-               return themeId;
-       }
-
-       public void setThemeId(String themeId) {
-               this.themeId = themeId;
-       }
-
-       public String getAdditionalHeaders() {
-               return additionalHeaders;
-       }
-
-       public void setAdditionalHeaders(String additionalHeaders) {
-               this.additionalHeaders = additionalHeaders;
-       }
-
-       public String getBodyHtml() {
-               return bodyHtml;
-       }
-
-       public void setBodyHtml(String bodyHtml) {
-               this.bodyHtml = bodyHtml;
-       }
-
-       public String getPageTitle() {
-               return pageTitle;
-       }
-
-       public void setPageTitle(String pageTitle) {
-               this.pageTitle = pageTitle;
-       }
-
-       public String getPageOverflow() {
-               return pageOverflow;
-       }
-
-       public void setPageOverflow(String pageOverflow) {
-               this.pageOverflow = pageOverflow;
-       }
-
-       public String getFavicon() {
-               return favicon;
-       }
-
-       public void setFavicon(String favicon) {
-               this.favicon = favicon;
-       }
-
-}
diff --git a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/Branding.java b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/Branding.java
deleted file mode 100644 (file)
index f72338e..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.argeo.cms.ui.script;
-
-import java.util.Map;
-
-public interface Branding {
-       public void applyBranding(Map<String, String> properties);
-
-       public String getThemeId();
-
-       public String getAdditionalHeaders();
-
-       public String getBodyHtml();
-
-       public String getPageTitle();
-
-       public String getPageOverflow();
-
-       public String getFavicon();
-
-}
diff --git a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/CmsScriptApp.java b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/CmsScriptApp.java
deleted file mode 100644 (file)
index 6b3a670..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-package org.argeo.cms.ui.script;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.PropertyType;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.script.ScriptEngine;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsTheme;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.ui.CmsUiConstants;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.web.BundleResourceLoader;
-import org.argeo.cms.web.SimpleErgonomics;
-import org.argeo.cms.web.WebThemeUtils;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.Application.OperationMode;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.eclipse.rap.rwt.application.ExceptionHandler;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.http.HttpContext;
-import org.osgi.service.http.HttpService;
-import org.osgi.service.http.NamespaceException;
-
-public class CmsScriptApp implements Branding {
-       public final static String CONTEXT_NAME = "contextName";
-
-       ServiceRegistration<ApplicationConfiguration> appConfigReg;
-
-       private ScriptEngine scriptEngine;
-
-       private final static CmsLog log = CmsLog.getLog(CmsScriptApp.class);
-
-       private String webPath;
-       private String repo = "(cn=node)";
-
-       // private Branding branding = new Branding();
-       private CmsTheme theme;
-
-       private List<String> resources = new ArrayList<>();
-
-       private Map<String, AppUi> ui = new HashMap<>();
-
-       private CmsUiProvider header;
-       private Integer headerHeight = null;
-       private CmsUiProvider lead;
-       private CmsUiProvider end;
-       private CmsUiProvider footer;
-
-       // Branding
-       private String themeId;
-       private String additionalHeaders;
-       private String bodyHtml;
-       private String pageTitle;
-       private String pageOverflow;
-       private String favicon;
-
-       public CmsScriptApp(ScriptEngine scriptEngine) {
-               super();
-               this.scriptEngine = scriptEngine;
-       }
-
-       public void apply(BundleContext bundleContext, Repository repository, Application application) {
-               BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
-
-               application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
-               // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
-
-               application.setExceptionHandler(new CmsExceptionHandler());
-
-               // loading animated gif
-               application.addResource(CmsUiConstants.LOADING_IMAGE, createResourceLoader(CmsUiConstants.LOADING_IMAGE));
-               // empty image
-               application.addResource(CmsUiConstants.NO_IMAGE, createResourceLoader(CmsUiConstants.NO_IMAGE));
-
-               for (String resource : resources) {
-                       application.addResource(resource, bundleRL);
-                       if (log.isTraceEnabled())
-                               log.trace("Resource " + resource);
-               }
-
-               if (theme != null) {
-                       WebThemeUtils.apply(application, theme);
-                       String themeHeaders = theme.getHtmlHeaders();
-                       if (themeHeaders != null) {
-                               if (additionalHeaders == null)
-                                       additionalHeaders = themeHeaders;
-                               else
-                                       additionalHeaders = themeHeaders + "\n" + additionalHeaders;
-                       }
-                       themeId = theme.getThemeId();
-               }
-
-               // client JavaScript
-               Bundle appBundle = bundleRL.getBundle();
-               BundleContext bc = appBundle.getBundleContext();
-               HttpService httpService = bc.getService(bc.getServiceReference(HttpService.class));
-               HttpContext httpContext = new BundleHttpContext(bc);
-               Enumeration<URL> themeResources = appBundle.findEntries("/js/", "*", true);
-               if (themeResources != null)
-                       bundleResources: while (themeResources.hasMoreElements()) {
-                               try {
-                                       String name = themeResources.nextElement().getPath();
-                                       if (name.endsWith("/"))
-                                               continue bundleResources;
-                                       String alias = "/" + getWebPath() + name;
-
-                                       httpService.registerResources(alias, name, httpContext);
-                                       if (log.isDebugEnabled())
-                                               log.debug("Mapped " + name + " to alias " + alias);
-
-                               } catch (NamespaceException e) {
-                                       // TODO Auto-generated catch block
-                                       e.printStackTrace();
-                               }
-                       }
-
-               // App UIs
-               for (String appUiName : ui.keySet()) {
-                       AppUi appUi = ui.get(appUiName);
-                       appUi.apply(repository, application, this, appUiName);
-
-               }
-
-       }
-
-       public void applySides(SimpleErgonomics simpleErgonomics) {
-               simpleErgonomics.setHeader(header);
-               simpleErgonomics.setLead(lead);
-               simpleErgonomics.setEnd(end);
-               simpleErgonomics.setFooter(footer);
-       }
-
-       public void register(BundleContext bundleContext, ApplicationConfiguration appConfig) {
-               Hashtable<String, String> props = new Hashtable<>();
-               props.put(CONTEXT_NAME, webPath);
-               appConfigReg = bundleContext.registerService(ApplicationConfiguration.class, appConfig, props);
-       }
-
-       public void reload() {
-               BundleContext bundleContext = appConfigReg.getReference().getBundle().getBundleContext();
-               ApplicationConfiguration appConfig = bundleContext.getService(appConfigReg.getReference());
-               appConfigReg.unregister();
-               register(bundleContext, appConfig);
-
-               // BundleContext bundleContext = (BundleContext)
-               // getScriptEngine().get("bundleContext");
-               // try {
-               // Bundle bundle = bundleContext.getBundle();
-               // bundle.stop();
-               // bundle.start();
-               // } catch (BundleException e) {
-               // // TODO Auto-generated catch block
-               // e.printStackTrace();
-               // }
-       }
-
-       private static ResourceLoader createResourceLoader(final String resourceName) {
-               return new ResourceLoader() {
-                       public InputStream getResourceAsStream(String resourceName) throws IOException {
-                               return getClass().getClassLoader().getResourceAsStream(resourceName);
-                       }
-               };
-       }
-
-       public List<String> getResources() {
-               return resources;
-       }
-
-       public AppUi newUi(String name) {
-               if (ui.containsKey(name))
-                       throw new IllegalArgumentException("There is already an UI named " + name);
-               AppUi appUi = new AppUi(this);
-               // appUi.setApp(this);
-               ui.put(name, appUi);
-               return appUi;
-       }
-
-       public void addUi(String name, AppUi appUi) {
-               if (ui.containsKey(name))
-                       throw new IllegalArgumentException("There is already an UI named " + name);
-               // appUi.setApp(this);
-               ui.put(name, appUi);
-       }
-
-       public void applyBranding(Map<String, String> properties) {
-               if (themeId != null)
-                       properties.put(WebClient.THEME_ID, themeId);
-               if (additionalHeaders != null)
-                       properties.put(WebClient.HEAD_HTML, additionalHeaders);
-               if (bodyHtml != null)
-                       properties.put(WebClient.BODY_HTML, bodyHtml);
-               if (pageTitle != null)
-                       properties.put(WebClient.PAGE_TITLE, pageTitle);
-               if (pageOverflow != null)
-                       properties.put(WebClient.PAGE_OVERFLOW, pageOverflow);
-               if (favicon != null)
-                       properties.put(WebClient.FAVICON, favicon);
-       }
-
-       class CmsExceptionHandler implements ExceptionHandler {
-
-               @Override
-               public void handleException(Throwable throwable) {
-                       // TODO be smarter
-                       CmsUiUtils.getCmsView().exception(throwable);
-               }
-
-       }
-
-       // public Branding getBranding() {
-       // return branding;
-       // }
-
-       ScriptEngine getScriptEngine() {
-               return scriptEngine;
-       }
-
-       public static String toJson(Node node) {
-               try {
-                       StringBuilder sb = new StringBuilder();
-                       sb.append('{');
-                       PropertyIterator pit = node.getProperties();
-                       int count = 0;
-                       while (pit.hasNext()) {
-                               Property p = pit.nextProperty();
-                               int type = p.getType();
-                               if (type == PropertyType.REFERENCE || type == PropertyType.WEAKREFERENCE || type == PropertyType.PATH) {
-                                       Node ref = p.getNode();
-                                       if (count != 0)
-                                               sb.append(',');
-                                       // TODO limit depth?
-                                       sb.append(toJson(ref));
-                                       count++;
-                               } else if (!p.isMultiple()) {
-                                       if (count != 0)
-                                               sb.append(',');
-                                       sb.append('\"').append(p.getName()).append("\":\"").append(p.getString()).append('\"');
-                                       count++;
-                               }
-                       }
-                       sb.append('}');
-                       return sb.toString();
-               } catch (RepositoryException e) {
-                       throw new CmsException("Cannot convert " + node + " to JSON", e);
-               }
-       }
-
-       public void fromJson(Node node, String json) {
-               // TODO
-       }
-
-       public CmsTheme getTheme() {
-               return theme;
-       }
-
-       public void setTheme(CmsTheme theme) {
-               this.theme = theme;
-       }
-
-       public String getWebPath() {
-               return webPath;
-       }
-
-       public void setWebPath(String context) {
-               this.webPath = context;
-       }
-
-       public String getRepo() {
-               return repo;
-       }
-
-       public void setRepo(String repo) {
-               this.repo = repo;
-       }
-
-       public Map<String, AppUi> getUi() {
-               return ui;
-       }
-
-       public void setUi(Map<String, AppUi> ui) {
-               this.ui = ui;
-       }
-
-       // Branding
-       public String getThemeId() {
-               return themeId;
-       }
-
-       public void setThemeId(String themeId) {
-               this.themeId = themeId;
-       }
-
-       public String getAdditionalHeaders() {
-               return additionalHeaders;
-       }
-
-       public void setAdditionalHeaders(String additionalHeaders) {
-               this.additionalHeaders = additionalHeaders;
-       }
-
-       public String getBodyHtml() {
-               return bodyHtml;
-       }
-
-       public void setBodyHtml(String bodyHtml) {
-               this.bodyHtml = bodyHtml;
-       }
-
-       public String getPageTitle() {
-               return pageTitle;
-       }
-
-       public void setPageTitle(String pageTitle) {
-               this.pageTitle = pageTitle;
-       }
-
-       public String getPageOverflow() {
-               return pageOverflow;
-       }
-
-       public void setPageOverflow(String pageOverflow) {
-               this.pageOverflow = pageOverflow;
-       }
-
-       public String getFavicon() {
-               return favicon;
-       }
-
-       public void setFavicon(String favicon) {
-               this.favicon = favicon;
-       }
-
-       public CmsUiProvider getHeader() {
-               return header;
-       }
-
-       public void setHeader(CmsUiProvider header) {
-               this.header = header;
-       }
-
-       public Integer getHeaderHeight() {
-               return headerHeight;
-       }
-
-       public void setHeaderHeight(Integer headerHeight) {
-               this.headerHeight = headerHeight;
-       }
-
-       public CmsUiProvider getLead() {
-               return lead;
-       }
-
-       public void setLead(CmsUiProvider lead) {
-               this.lead = lead;
-       }
-
-       public CmsUiProvider getEnd() {
-               return end;
-       }
-
-       public void setEnd(CmsUiProvider end) {
-               this.end = end;
-       }
-
-       public CmsUiProvider getFooter() {
-               return footer;
-       }
-
-       public void setFooter(CmsUiProvider footer) {
-               this.footer = footer;
-       }
-
-       static class BundleHttpContext implements HttpContext {
-               private BundleContext bundleContext;
-
-               public BundleHttpContext(BundleContext bundleContext) {
-                       super();
-                       this.bundleContext = bundleContext;
-               }
-
-               @Override
-               public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
-                       // TODO Auto-generated method stub
-                       return true;
-               }
-
-               @Override
-               public URL getResource(String name) {
-
-                       return bundleContext.getBundle().getEntry(name);
-               }
-
-               @Override
-               public String getMimeType(String name) {
-                       return null;
-               }
-
-       }
-
-}
diff --git a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/CmsScriptRwtApplication.java b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/CmsScriptRwtApplication.java
deleted file mode 100644 (file)
index 9879fb0..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-package org.argeo.cms.ui.script;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.net.URL;
-
-import javax.jcr.Repository;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.swt.CmsException;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.wiring.BundleWiring;
-
-public class CmsScriptRwtApplication implements ApplicationConfiguration {
-       public final static String APP = "APP";
-       public final static String BC = "BC";
-
-       private final CmsLog log = CmsLog.getLog(CmsScriptRwtApplication.class);
-
-       BundleContext bundleContext;
-       Repository repository;
-
-       ScriptEngine engine;
-
-       public void init(BundleContext bundleContext) {
-               this.bundleContext = bundleContext;
-               ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
-               ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
-               try {
-//                     Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
-//                     ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
-//                     engine = scriptEngineManager.getEngineByName("JavaScript");
-//                     if (engine == null) {// Nashorn
-//                             Thread.currentThread().setContextClassLoader(originalCcl);
-//                             scriptEngineManager = new ScriptEngineManager();
-//                             Thread.currentThread().setContextClassLoader(bundleCl);
-//                             engine = scriptEngineManager.getEngineByName("JavaScript");
-//                     }
-                       engine = loadScriptEngine(originalCcl, bundleCl);
-
-                       // Load script
-                       URL appUrl = bundleContext.getBundle().getEntry("cms/app.js");
-                       // System.out.println("Loading " + appUrl);
-                       // System.out.println("Loading " + appUrl.getHost());
-                       // System.out.println("Loading " + appUrl.getPath());
-
-                       CmsScriptApp app = new CmsScriptApp(engine);
-                       engine.put(APP, app);
-                       engine.put(BC, bundleContext);
-                       try (Reader reader = new InputStreamReader(appUrl.openStream())) {
-                               engine.eval(reader);
-                       } catch (IOException | ScriptException e) {
-                               throw new CmsException("Cannot execute " + appUrl, e);
-                       }
-
-                       if (log.isDebugEnabled())
-                               log.debug("CMS script app initialized from " + appUrl);
-
-               } catch (Exception e) {
-                       e.printStackTrace();
-               } finally {
-                       Thread.currentThread().setContextClassLoader(originalCcl);
-               }
-       }
-
-       public void destroy(BundleContext bundleContext) {
-               engine = null;
-       }
-
-       @Override
-       public void configure(Application application) {
-               load(application);
-       }
-
-       void load(Application application) {
-               CmsScriptApp app = getApp();
-               app.apply(bundleContext, repository, application);
-               if (log.isDebugEnabled())
-                       log.debug("CMS script app loaded to " + app.getWebPath());
-       }
-
-       CmsScriptApp getApp() {
-               if (engine == null)
-                       throw new IllegalStateException("CMS script app is not initialized");
-               return (CmsScriptApp) engine.get(APP);
-       }
-
-       void update() {
-
-               try {
-                       bundleContext.getBundle().update();
-               } catch (BundleException e) {
-                       e.printStackTrace();
-               }
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-       private static ScriptEngine loadScriptEngine(ClassLoader originalCcl, ClassLoader bundleCl) {
-               Thread.currentThread().setContextClassLoader(bundleCl);// GraalVM needs it to be before creating manager
-               ScriptEngineManager scriptEngineManager = new ScriptEngineManager(bundleCl);
-               ScriptEngine engine = scriptEngineManager.getEngineByName("JavaScript");
-               if (engine == null) {// Nashorn
-                       Thread.currentThread().setContextClassLoader(originalCcl);
-                       scriptEngineManager = new ScriptEngineManager();
-                       Thread.currentThread().setContextClassLoader(bundleCl);
-                       engine = scriptEngineManager.getEngineByName("JavaScript");
-               }
-               return engine;
-       }
-}
diff --git a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/ScriptAppActivator.java b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/ScriptAppActivator.java
deleted file mode 100644 (file)
index a550953..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.argeo.cms.ui.script;
-
-import javax.jcr.Repository;
-
-import org.argeo.api.cms.CmsLog;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-public class ScriptAppActivator implements BundleActivator {
-       private final static CmsLog log = CmsLog.getLog(ScriptAppActivator.class);
-
-       @Override
-       public void start(BundleContext context) throws Exception {
-               try {
-                       CmsScriptRwtApplication appConfig = new CmsScriptRwtApplication();
-                       appConfig.init(context);
-                       CmsScriptApp app = appConfig.getApp();
-                       ServiceTracker<Repository, Repository> repoSt = new ServiceTracker<Repository, Repository>(context,
-                                       FrameworkUtil.createFilter("(&" + app.getRepo() + "(objectClass=javax.jcr.Repository))"), null) {
-
-                               @Override
-                               public Repository addingService(ServiceReference<Repository> reference) {
-                                       Repository repository = super.addingService(reference);
-                                       appConfig.setRepository(repository);
-                                       CmsScriptApp app = appConfig.getApp();
-                                       app.register(context, appConfig);
-                                       return repository;
-                               }
-
-                       };
-                       repoSt.open();
-               } catch (Exception e) {
-                       log.error("Cannot initialise script bundle " + context.getBundle().getSymbolicName(), e);
-                       throw e;
-               }
-       }
-
-       @Override
-       public void stop(BundleContext context) throws Exception {
-       }
-
-}
diff --git a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/ScriptUi.java b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/ScriptUi.java
deleted file mode 100644 (file)
index 0c870e1..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-package org.argeo.cms.ui.script;
-
-import java.net.URL;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.script.Invocable;
-import javax.script.ScriptEngine;
-import javax.script.ScriptException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.osgi.framework.BundleContext;
-
-class ScriptUi implements CmsUiProvider {
-       private final static CmsLog log = CmsLog.getLog(ScriptUi.class);
-
-       private boolean development = true;
-       private ScriptEngine scriptEngine;
-
-       private URL appUrl;
-       // private BundleContext bundleContext;
-       // private String path;
-
-       // private Bindings bindings;
-       // private String script;
-
-       public ScriptUi(BundleContext bundleContext,ScriptEngine scriptEngine, String path) {
-               this.scriptEngine = scriptEngine;
-////           ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
-//             ClassLoader bundleCl = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
-//             ClassLoader originalCcl = Thread.currentThread().getContextClassLoader();
-//             try {
-////                   Thread.currentThread().setContextClassLoader(bundleCl);
-////                   scriptEngine = scriptEngineManager.getEngineByName("JavaScript");
-////                   scriptEngine.put(CmsScriptRwtApplication.BC, bundleContext);
-//                     scriptEngine = CmsScriptRwtApplication.loadScriptEngine(originalCcl, bundleCl);
-//
-//             } catch (Exception e) {
-//                     e.printStackTrace();
-//             } finally {
-//                     Thread.currentThread().setContextClassLoader(originalCcl);
-//             }
-               this.appUrl = bundleContext.getBundle().getEntry(path);
-               load();
-       }
-
-       private void load() {
-//             try (Reader reader = new InputStreamReader(appUrl.openStream())) {
-//                     scriptEngine.eval(reader);
-//             } catch (IOException | ScriptException e) {
-//                     log.warn("Cannot execute " + appUrl, e);
-//             }
-
-               try {
-                       scriptEngine.eval("load('" + appUrl + "')");
-               } catch (ScriptException e) {
-                       log.warn("Cannot execute " + appUrl, e);
-               }
-
-       }
-
-       // public ScriptUiProvider(ScriptEngine scriptEngine, String script) throws
-       // ScriptException {
-       // super();
-       // this.scriptEngine = scriptEngine;
-       // this.script = script;
-       // bindings = scriptEngine.createBindings();
-       // scriptEngine.eval(script, bindings);
-       // }
-
-       @Override
-       public Control createUi(Composite parent, Node context) throws RepositoryException {
-               long begin = System.currentTimeMillis();
-               // if (bindings == null) {
-               // bindings = scriptEngine.createBindings();
-               // try {
-               // scriptEngine.eval(script, bindings);
-               // } catch (ScriptException e) {
-               // log.warn("Cannot evaluate script", e);
-               // }
-               // }
-               // Bindings bindings = scriptEngine.createBindings();
-               // bindings.put("parent", parent);
-               // bindings.put("context", context);
-               // URL appUrl = bundleContext.getBundle().getEntry(path);
-               // try (Reader reader = new InputStreamReader(appUrl.openStream())) {
-               // scriptEngine.eval(reader,bindings);
-               // } catch (IOException | ScriptException e) {
-               // log.warn("Cannot execute " + appUrl, e);
-               // }
-
-               if (development)
-                       load();
-
-               Invocable invocable = (Invocable) scriptEngine;
-               try {
-                       invocable.invokeFunction("createUi", parent, context);
-               } catch (NoSuchMethodException e) {
-                       // TODO Auto-generated catch block
-                       e.printStackTrace();
-               } catch (ScriptException e) {
-                       // TODO Auto-generated catch block
-                       e.printStackTrace();
-               }
-
-               long duration = System.currentTimeMillis() - begin;
-               if (log.isTraceEnabled())
-                       log.trace(appUrl + " UI in " + duration + " ms");
-               return null;
-       }
-
-}
diff --git a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/cms.js b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/cms.js
deleted file mode 100644 (file)
index be9618d..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-// CMS
-var ScrolledPage = Java.type('org.argeo.cms.ui.widgets.ScrolledPage');
-
-var CmsScriptApp = Java.type('org.argeo.cms.ui.script.CmsScriptApp');
-var AppUi = Java.type('org.argeo.cms.ui.script.AppUi');
-var Theme = Java.type('org.argeo.cms.ui.script.Theme');
-var ScriptUi = Java.type('org.argeo.cms.ui.script.ScriptUi');
-var CmsUtils = Java.type('org.argeo.cms.ui.util.CmsUiUtils');
-var SimpleCmsHeader = Java.type('org.argeo.cms.ui.util.SimpleCmsHeader');
-var CmsLink = Java.type('org.argeo.cms.ui.util.CmsLink');
-var MenuLink = Java.type('org.argeo.cms.ui.util.MenuLink');
-var UserMenuLink = Java.type('org.argeo.cms.ui.util.UserMenuLink');
-
-// SWT
-var SWT = Java.type('org.eclipse.swt.SWT');
-var Composite = Java.type('org.eclipse.swt.widgets.Composite');
-var Label = Java.type('org.eclipse.swt.widgets.Label');
-var Button = Java.type('org.eclipse.swt.widgets.Button');
-var Text = Java.type('org.eclipse.swt.widgets.Text');
-var Browser = Java.type('org.eclipse.swt.browser.Browser');
-
-var FillLayout = Java.type('org.eclipse.swt.layout.FillLayout');
-var GridLayout = Java.type('org.eclipse.swt.layout.GridLayout');
-var RowLayout = Java.type('org.eclipse.swt.layout.RowLayout');
-var FormLayout = Java.type('org.eclipse.swt.layout.FormLayout');
-var GridData = Java.type('org.eclipse.swt.layout.GridData');
-
-function loadNode(node) {
-       var json = CmsScriptApp.toJson(node)
-       var fromJson = JSON.parse(json)
-       return fromJson
-}
-
-function newArea(parent, style, layout) {
-       var control = new Composite(parent, SWT.NONE)
-       control.setLayout(layout)
-       CmsUtils.style(control, style)
-       return control
-}
-
-function newLabel(parent, style, text) {
-       var control = new Label(parent, SWT.WRAP)
-       control.setText(text)
-       CmsUtils.style(control, style)
-       CmsUtils.markup(control)
-       return control
-}
-
-function newButton(parent, style, text) {
-       var control = new Button(parent, SWT.FLAT)
-       control.setText(text)
-       CmsUtils.style(control, style)
-       CmsUtils.markup(control)
-       return control
-}
-
-function newFormLabel(parent, style, text) {
-       return newLabel(parent, style, '<b>' + text + '</b>')
-}
-
-function newText(parent, style, msg) {
-       var control = new Text(parent, SWT.NONE)
-       control.setMessage(msg)
-       CmsUtils.style(control, style)
-       return control
-}
-
-function newScrolledPage(parent) {
-       var scrolled = new ScrolledPage(parent, SWT.NONE)
-       scrolled.setLayoutData(CmsUtils.fillAll())
-       scrolled.setLayout(CmsUtils.noSpaceGridLayout())
-       var page = new Composite(scrolled, SWT.NONE)
-       page.setLayout(CmsUtils.noSpaceGridLayout())
-       page.setBackgroundMode(SWT.INHERIT_NONE)
-       return page
-}
-
-function gridData(control) {
-       var gridData = new GridData()
-       control.setLayoutData(gridData)
-       return gridData
-}
-
-function gridData(control, hAlign, vAlign) {
-       var gridData = new GridData(hAlign, vAlign, false, false)
-       control.setLayoutData(gridData)
-       return gridData
-}
-
-// print(__FILE__, __LINE__, __DIR__)
diff --git a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/package-info.java b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/ui/script/package-info.java
deleted file mode 100644 (file)
index 7440596..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Argeo CMS user interface scripting. */
-package org.argeo.cms.ui.script;
\ No newline at end of file
diff --git a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/AbstractCmsEntryPoint.java b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/AbstractCmsEntryPoint.java
deleted file mode 100644 (file)
index f3269f2..0000000
+++ /dev/null
@@ -1,398 +0,0 @@
-package org.argeo.cms.web;
-
-import static org.argeo.util.directory.ldap.SharedSecret.X_SHARED_SECRET;
-
-import java.io.IOException;
-import java.security.PrivilegedAction;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import javax.security.auth.Subject;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-import javax.servlet.http.HttpServletRequest;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsView;
-import org.argeo.api.cms.CmsAuth;
-import org.argeo.cms.auth.CurrentUser;
-import org.argeo.cms.auth.RemoteAuthCallback;
-import org.argeo.cms.auth.RemoteAuthCallbackHandler;
-import org.argeo.cms.servlet.ServletHttpRequest;
-import org.argeo.cms.servlet.ServletHttpResponse;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.swt.CmsStyles;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.eclipse.ui.specific.UiContext;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.util.directory.ldap.AuthPassword;
-import org.argeo.util.directory.ldap.SharedSecret;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.AbstractEntryPoint;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.client.service.BrowserNavigation;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
-import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-
-/** Manages history and navigation */
-@Deprecated
-public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implements CmsView {
-       private static final long serialVersionUID = 906558779562569784L;
-
-       private final CmsLog log = CmsLog.getLog(AbstractCmsEntryPoint.class);
-
-       // private final Subject subject;
-       private LoginContext loginContext;
-
-       private final Repository repository;
-       private final String workspace;
-       private final String defaultPath;
-       private final Map<String, String> factoryProperties;
-
-       // Current state
-       private Session session;
-       private Node node;
-       private String nodePath;// useful when changing auth
-       private String state;
-       private Throwable exception;
-
-       // Client services
-       private final JavaScriptExecutor jsExecutor;
-       private final BrowserNavigation browserNavigation;
-
-       public AbstractCmsEntryPoint(Repository repository, String workspace, String defaultPath,
-                       Map<String, String> factoryProperties) {
-               this.repository = repository;
-               this.workspace = workspace;
-               this.defaultPath = defaultPath;
-               this.factoryProperties = new HashMap<String, String>(factoryProperties);
-               // subject = new Subject();
-
-               // Initial login
-               LoginContext lc;
-               try {
-                       lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER,
-                                       new RemoteAuthCallbackHandler(new ServletHttpRequest(UiContext.getHttpRequest()),
-                                                       new ServletHttpResponse(UiContext.getHttpResponse())));
-                       lc.login();
-               } catch (LoginException e) {
-                       try {
-                               lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS);
-                               lc.login();
-                       } catch (LoginException e1) {
-                               throw new CmsException("Cannot log in as anonymous", e1);
-                       }
-               }
-               authChange(lc);
-
-               jsExecutor = RWT.getClient().getService(JavaScriptExecutor.class);
-               browserNavigation = RWT.getClient().getService(BrowserNavigation.class);
-               if (browserNavigation != null)
-                       browserNavigation.addBrowserNavigationListener(new CmsNavigationListener());
-       }
-
-       @Override
-       protected Shell createShell(Display display) {
-               Shell shell = super.createShell(display);
-               shell.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_SHELL);
-               display.disposeExec(new Runnable() {
-
-                       @Override
-                       public void run() {
-                               if (log.isTraceEnabled())
-                                       log.trace("Logging out " + session);
-                               JcrUtils.logoutQuietly(session);
-                       }
-               });
-               return shell;
-       }
-
-       @Override
-       protected final void createContents(final Composite parent) {
-               // UiContext.setData(CmsView.KEY, this);
-               CmsSwtUtils.registerCmsView(parent.getShell(), this);
-               Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
-                       @Override
-                       public Void run() {
-                               try {
-                                       initUi(parent);
-                               } catch (Exception e) {
-                                       throw new CmsException("Cannot create entrypoint contents", e);
-                               }
-                               return null;
-                       }
-               });
-       }
-
-       /** Create UI */
-       protected abstract void initUi(Composite parent);
-
-       /** Recreate UI after navigation or auth change */
-       protected abstract void refresh();
-
-       /**
-        * The node to return when no node was found (for authenticated users and
-        * anonymous)
-        */
-//     private Node getDefaultNode(Session session) throws RepositoryException {
-//             if (!session.hasPermission(defaultPath, "read")) {
-//                     String userId = session.getUserID();
-//                     if (userId.equals(NodeConstants.ROLE_ANONYMOUS))
-//                             // TODO throw a special exception
-//                             throw new CmsException("Login required");
-//                     else
-//                             throw new CmsException("Unauthorized");
-//             }
-//             return session.getNode(defaultPath);
-//     }
-
-       protected String getBaseTitle() {
-               return factoryProperties.get(WebClient.PAGE_TITLE);
-       }
-
-       public void navigateTo(String state) {
-               exception = null;
-               String title = setState(state);
-               doRefresh();
-               if (browserNavigation != null)
-                       browserNavigation.pushState(state, title);
-       }
-
-       // @Override
-       // public synchronized Subject getSubject() {
-       // return subject;
-       // }
-
-       // @Override
-       // public LoginContext getLoginContext() {
-       // return loginContext;
-       // }
-       protected Subject getSubject() {
-               return loginContext.getSubject();
-       }
-
-       @Override
-       public boolean isAnonymous() {
-               return CurrentUser.isAnonymous(getSubject());
-       }
-
-       @Override
-       public synchronized void logout() {
-               if (loginContext == null)
-                       throw new CmsException("Login context should not be null");
-               try {
-                       CurrentUser.logoutCmsSession(loginContext.getSubject());
-                       loginContext.logout();
-                       LoginContext anonymousLc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS);
-                       anonymousLc.login();
-                       authChange(anonymousLc);
-               } catch (LoginException e) {
-                       log.error("Cannot logout", e);
-               }
-       }
-
-       @Override
-       public synchronized void authChange(LoginContext lc) {
-               if (lc == null)
-                       throw new CmsException("Login context cannot be null");
-               // logout previous login context
-               if (this.loginContext != null)
-                       try {
-                               this.loginContext.logout();
-                       } catch (LoginException e1) {
-                               log.warn("Could not log out: " + e1);
-                       }
-               this.loginContext = lc;
-               Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
-
-                       @Override
-                       public Void run() {
-                               try {
-                                       JcrUtils.logoutQuietly(session);
-                                       session = repository.login(workspace);
-                                       if (nodePath != null)
-                                               try {
-                                                       node = session.getNode(nodePath);
-                                               } catch (PathNotFoundException e) {
-                                                       navigateTo("~");
-                                               }
-
-                                       // refresh UI
-                                       doRefresh();
-                               } catch (RepositoryException e) {
-                                       throw new CmsException("Cannot perform auth change", e);
-                               }
-                               return null;
-                       }
-
-               });
-       }
-
-       @Override
-       public void exception(final Throwable e) {
-               AbstractCmsEntryPoint.this.exception = e;
-               log.error("Unexpected exception in CMS", e);
-               doRefresh();
-       }
-
-       protected synchronized void doRefresh() {
-               Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
-                       @Override
-                       public Void run() {
-                               refresh();
-                               return null;
-                       }
-               });
-       }
-
-       /** Sets the state of the entry point and retrieve the related JCR node. */
-       protected synchronized String setState(String newState) {
-               String previousState = this.state;
-
-               String newNodePath = null;
-               String prefix = null;
-               this.state = newState;
-               if (newState.equals("~"))
-                       this.state = "";
-
-               try {
-                       int firstSlash = state.indexOf('/');
-                       if (firstSlash == 0) {
-                               newNodePath = state;
-                               prefix = "";
-                       } else if (firstSlash > 0) {
-                               prefix = state.substring(0, firstSlash);
-                               newNodePath = state.substring(firstSlash);
-                       } else {
-                               newNodePath = defaultPath;
-                               prefix = state;
-
-                       }
-
-                       // auth
-                       int colonIndex = prefix.indexOf('$');
-                       if (colonIndex > 0) {
-                               SharedSecret token = new SharedSecret(new AuthPassword(X_SHARED_SECRET + '$' + prefix)) {
-
-                                       @Override
-                                       public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
-                                               super.handle(callbacks);
-                                               // handle HTTP context
-                                               for (Callback callback : callbacks) {
-                                                       if (callback instanceof RemoteAuthCallback) {
-                                                               ((RemoteAuthCallback) callback)
-                                                                               .setRequest(new ServletHttpRequest(UiContext.getHttpRequest()));
-                                                               ((RemoteAuthCallback) callback)
-                                                                               .setResponse(new ServletHttpResponse(UiContext.getHttpResponse()));
-                                                       }
-                                               }
-                                       }
-                               };
-                               LoginContext lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER, token);
-                               lc.login();
-                               authChange(lc);// sets the node as well
-                               // } else {
-                               // // TODO check consistency
-                               // }
-                       } else {
-                               Node newNode = null;
-                               if (session.nodeExists(newNodePath))
-                                       newNode = session.getNode(newNodePath);
-                               else {
-//                                     throw new CmsException("Data " + newNodePath + " does not exist");
-                                       newNode = null;
-                               }
-                               setNode(newNode);
-                       }
-                       String title = publishMetaData(getNode());
-
-                       if (log.isTraceEnabled())
-                               log.trace("node=" + newNodePath + ", state=" + state + " (prefix=" + prefix + ")");
-
-                       return title;
-               } catch (Exception e) {
-                       log.error("Cannot set state '" + state + "'", e);
-                       if (state.equals("") || newState.equals("~") || newState.equals(previousState))
-                               return "Unrecoverable exception : " + e.getClass().getSimpleName();
-                       if (previousState.equals(""))
-                               previousState = "~";
-                       navigateTo(previousState);
-                       throw new CmsException("Unexpected issue when accessing #" + newState, e);
-               }
-       }
-
-       private String publishMetaData(Node node) throws RepositoryException {
-               // Title
-               String title;
-               if (node != null && node.isNodeType(NodeType.MIX_TITLE) && node.hasProperty(Property.JCR_TITLE))
-                       title = node.getProperty(Property.JCR_TITLE).getString() + " - " + getBaseTitle();
-               else
-                       title = getBaseTitle();
-
-               HttpServletRequest request = UiContext.getHttpRequest();
-               if (request == null)
-                       return null;
-
-               StringBuilder js = new StringBuilder();
-               if (title == null)
-                       title = "";
-               title = title.replace("'", "\\'");// sanitize
-               js.append("document.title = '" + title + "';");
-               jsExecutor.execute(js.toString());
-               return title;
-       }
-
-       // Simply remove some illegal character
-       // private String clean(String stringToClean) {
-       // return stringToClean.replaceAll("'", "").replaceAll("\\n", "")
-       // .replaceAll("\\t", "");
-       // }
-
-       protected synchronized Node getNode() {
-               return node;
-       }
-
-       private synchronized void setNode(Node node) throws RepositoryException {
-               this.node = node;
-               this.nodePath = node == null ? null : node.getPath();
-       }
-
-       protected String getState() {
-               return state;
-       }
-
-       protected Throwable getException() {
-               return exception;
-       }
-
-       protected void resetException() {
-               exception = null;
-       }
-
-       protected Session getSession() {
-               return session;
-       }
-
-       private class CmsNavigationListener implements BrowserNavigationListener {
-               private static final long serialVersionUID = -3591018803430389270L;
-
-               @Override
-               public void navigated(BrowserNavigationEvent event) {
-                       setState(event.getState());
-                       doRefresh();
-               }
-       }
-}
\ No newline at end of file
index 1597197207377c27342229c13f4c01ee8a852119..477a6569dc5ed4e4d193e24be7493185dc67beaa 100644 (file)
@@ -27,8 +27,8 @@ import org.argeo.cms.servlet.ServletHttpRequest;
 import org.argeo.cms.servlet.ServletHttpResponse;
 import org.argeo.cms.swt.CmsSwtUtils;
 import org.argeo.cms.swt.SimpleSwtUxContext;
+import org.argeo.cms.swt.acr.AcrSwtImageManager;
 import org.argeo.cms.swt.dialogs.CmsFeedback;
-import org.argeo.cms.ui.util.DefaultImageManager;
 import org.argeo.eclipse.ui.specific.UiContext;
 import org.eclipse.rap.rwt.RWT;
 import org.eclipse.rap.rwt.application.EntryPoint;
@@ -111,7 +111,7 @@ public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationL
                        public Void run() {
                                try {
                                        uxContext = new SimpleSwtUxContext();
-                                       imageManager = new DefaultImageManager();
+                                       imageManager = (CmsImageManager) new AcrSwtImageManager();
                                        CmsSession cmsSession = getCmsSession();
                                        if (cmsSession != null) {
                                                UiContext.setLocale(cmsSession.getLocale());
diff --git a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/SimpleApp.java b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/SimpleApp.java
deleted file mode 100644 (file)
index 38a9b44..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-package org.argeo.cms.web;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.security.Privilege;
-import javax.jcr.version.VersionManager;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.ui.CmsUiConstants;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.LifeCycleUiProvider;
-import org.argeo.cms.ui.util.CmsUiUtils;
-import org.argeo.cms.ui.util.StyleSheetResourceLoader;
-import org.argeo.jcr.JcrUtils;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.application.Application;
-import org.eclipse.rap.rwt.application.Application.OperationMode;
-import org.eclipse.rap.rwt.application.ApplicationConfiguration;
-import org.eclipse.rap.rwt.application.EntryPoint;
-import org.eclipse.rap.rwt.application.EntryPointFactory;
-import org.eclipse.rap.rwt.application.ExceptionHandler;
-import org.eclipse.rap.rwt.client.WebClient;
-import org.eclipse.rap.rwt.client.service.JavaScriptExecutor;
-import org.eclipse.rap.rwt.service.ResourceLoader;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-
-/** A basic generic app based on {@link SimpleErgonomics}. */
-@Deprecated
-public class SimpleApp implements CmsUiConstants, ApplicationConfiguration {
-       private final static CmsLog log = CmsLog.getLog(SimpleApp.class);
-
-       private String contextName = null;
-
-       private Map<String, Map<String, String>> branding = new HashMap<String, Map<String, String>>();
-       private Map<String, List<String>> styleSheets = new HashMap<String, List<String>>();
-
-       private List<String> resources = new ArrayList<String>();
-
-       private BundleContext bundleContext;
-
-       private Repository repository;
-       private String workspace = null;
-       private String jcrBasePath = "/";
-       private List<String> roPrincipals = Arrays.asList(CmsConstants.ROLE_ANONYMOUS, CmsConstants.ROLE_USER);
-       private List<String> rwPrincipals = Arrays.asList(CmsConstants.ROLE_USER);
-
-       private CmsUiProvider header;
-       private Map<String, CmsUiProvider> pages = new LinkedHashMap<String, CmsUiProvider>();
-
-       private Integer headerHeight = 40;
-
-       private ServiceRegistration<ApplicationConfiguration> appReg;
-
-       public void configure(Application application) {
-               try {
-                       BundleResourceLoader bundleRL = new BundleResourceLoader(bundleContext.getBundle());
-
-                       application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
-                       // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
-
-                       application.setExceptionHandler(new CmsExceptionHandler());
-
-                       // loading animated gif
-                       application.addResource(LOADING_IMAGE, createResourceLoader(LOADING_IMAGE));
-                       // empty image
-                       application.addResource(NO_IMAGE, createResourceLoader(NO_IMAGE));
-
-                       for (String resource : resources) {
-                               application.addResource(resource, bundleRL);
-                               if (log.isTraceEnabled())
-                                       log.trace("Resource " + resource);
-                       }
-
-                       Map<String, String> defaultBranding = null;
-                       if (branding.containsKey("*"))
-                               defaultBranding = branding.get("*");
-                       // String defaultTheme = defaultBranding.get(WebClient.THEME_ID);
-
-                       // entry points
-                       for (String page : pages.keySet()) {
-                               Map<String, String> properties = defaultBranding != null ? new HashMap<String, String>(defaultBranding)
-                                               : new HashMap<String, String>();
-                               if (branding.containsKey(page)) {
-                                       properties.putAll(branding.get(page));
-                               }
-                               // favicon
-                               if (properties.containsKey(WebClient.FAVICON)) {
-                                       String themeId = defaultBranding.get(WebClient.THEME_ID);
-                                       Bundle themeBundle = findThemeBundle(bundleContext, themeId);
-                                       String faviconRelPath = properties.get(WebClient.FAVICON);
-                                       application.addResource(faviconRelPath,
-                                                       new BundleResourceLoader(themeBundle != null ? themeBundle : bundleContext.getBundle()));
-                                       if (log.isTraceEnabled())
-                                               log.trace("Favicon " + faviconRelPath);
-
-                               }
-
-                               // page title
-                               if (!properties.containsKey(WebClient.PAGE_TITLE)) {
-                                       if (page.length() > 0)
-                                               properties.put(WebClient.PAGE_TITLE, Character.toUpperCase(page.charAt(0)) + page.substring(1));
-                               }
-
-                               // default body HTML
-                               if (!properties.containsKey(WebClient.BODY_HTML))
-                                       properties.put(WebClient.BODY_HTML, DEFAULT_LOADING_BODY);
-
-                               //
-                               // ADD ENTRY POINT
-                               //
-                               application.addEntryPoint("/" + page,
-                                               new CmsEntryPointFactory(pages.get(page), repository, workspace, properties), properties);
-                               log.info("Page /" + page);
-                       }
-
-                       // stylesheets and themes
-                       Set<Bundle> themeBundles = new HashSet<>();
-                       for (String themeId : styleSheets.keySet()) {
-                               Bundle themeBundle = findThemeBundle(bundleContext, themeId);
-                               StyleSheetResourceLoader styleSheetRL = new StyleSheetResourceLoader(
-                                               themeBundle != null ? themeBundle : bundleContext.getBundle());
-                               if (themeBundle != null)
-                                       themeBundles.add(themeBundle);
-                               List<String> cssLst = styleSheets.get(themeId);
-                               if (log.isDebugEnabled())
-                                       log.debug("Theme " + themeId);
-                               for (String css : cssLst) {
-                                       application.addStyleSheet(themeId, css, styleSheetRL);
-                                       if (log.isDebugEnabled())
-                                               log.debug(" CSS " + css);
-                               }
-
-                       }
-                       for (Bundle themeBundle : themeBundles) {
-                               BundleResourceLoader themeBRL = new BundleResourceLoader(themeBundle);
-                               SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.png");
-                               SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.gif");
-                               SimpleApp.addThemeResources(application, themeBundle, themeBRL, "*.jpg");
-                       }
-               } catch (RuntimeException e) {
-                       // Easier access to initialisation errors
-                       log.error("Unexpected exception when configuring RWT application.", e);
-                       throw e;
-               }
-       }
-
-       public void init() throws RepositoryException {
-               Session session = null;
-               try {
-                       session = CmsJcrUtils.openDataAdminSession(repository, workspace);
-                       // session = JcrUtils.loginOrCreateWorkspace(repository, workspace);
-                       VersionManager vm = session.getWorkspace().getVersionManager();
-                       JcrUtils.mkdirs(session, jcrBasePath);
-                       session.save();
-                       if (!vm.isCheckedOut(jcrBasePath))
-                               vm.checkout(jcrBasePath);
-                       for (String principal : rwPrincipals)
-                               JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_WRITE);
-                       for (String principal : roPrincipals)
-                               JcrUtils.addPrivilege(session, jcrBasePath, principal, Privilege.JCR_READ);
-
-                       for (String pageName : pages.keySet()) {
-                               try {
-                                       initPage(session, pages.get(pageName));
-                                       session.save();
-                               } catch (Exception e) {
-                                       throw new CmsException("Cannot initialize page " + pageName, e);
-                               }
-                       }
-
-               } finally {
-                       JcrUtils.logoutQuietly(session);
-               }
-
-               // publish to OSGi
-               register();
-       }
-
-       protected void initPage(Session adminSession, CmsUiProvider page) throws RepositoryException {
-               if (page instanceof LifeCycleUiProvider)
-                       ((LifeCycleUiProvider) page).init(adminSession);
-       }
-
-       public void destroy() {
-               for (String pageName : pages.keySet()) {
-                       try {
-                               CmsUiProvider page = pages.get(pageName);
-                               if (page instanceof LifeCycleUiProvider)
-                                       ((LifeCycleUiProvider) page).destroy();
-                       } catch (Exception e) {
-                               log.error("Cannot destroy page " + pageName, e);
-                       }
-               }
-       }
-
-       protected void register() {
-               Hashtable<String, String> props = new Hashtable<String, String>();
-               if (contextName != null)
-                       props.put("contextName", contextName);
-               appReg = bundleContext.registerService(ApplicationConfiguration.class, this, props);
-               if (log.isDebugEnabled())
-                       log.debug("Registered " + (contextName == null ? "/" : contextName));
-       }
-
-       protected void unregister() {
-               appReg.unregister();
-               if (log.isDebugEnabled())
-                       log.debug("Unregistered " + (contextName == null ? "/" : contextName));
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-       public void setWorkspace(String workspace) {
-               this.workspace = workspace;
-       }
-
-       public void setHeader(CmsUiProvider header) {
-               this.header = header;
-       }
-
-       public void setPages(Map<String, CmsUiProvider> pages) {
-               this.pages = pages;
-       }
-
-       public void setJcrBasePath(String basePath) {
-               this.jcrBasePath = basePath;
-       }
-
-       public void setRoPrincipals(List<String> roPrincipals) {
-               this.roPrincipals = roPrincipals;
-       }
-
-       public void setRwPrincipals(List<String> rwPrincipals) {
-               this.rwPrincipals = rwPrincipals;
-       }
-
-       public void setHeaderHeight(Integer headerHeight) {
-               this.headerHeight = headerHeight;
-       }
-
-       public void setBranding(Map<String, Map<String, String>> branding) {
-               this.branding = branding;
-       }
-
-       public void setStyleSheets(Map<String, List<String>> styleSheets) {
-               this.styleSheets = styleSheets;
-       }
-
-       public void setBundleContext(BundleContext bundleContext) {
-               this.bundleContext = bundleContext;
-       }
-
-       public void setResources(List<String> resources) {
-               this.resources = resources;
-       }
-
-       public void setContextName(String contextName) {
-               this.contextName = contextName;
-       }
-
-       private static void addThemeResources(Application application, Bundle themeBundle, BundleResourceLoader themeBRL,
-                       String pattern) {
-               Enumeration<URL> themeResources = themeBundle.findEntries("/", pattern, true);
-               if (themeResources == null)
-                       return;
-               while (themeResources.hasMoreElements()) {
-                       String resource = themeResources.nextElement().getPath();
-                       // remove first '/' so that RWT registers it
-                       resource = resource.substring(1);
-                       if (!resource.endsWith("/")) {
-                               application.addResource(resource, themeBRL);
-                               if (log.isTraceEnabled())
-                                       log.trace("Registered " + resource + " from theme " + themeBundle);
-                       }
-
-               }
-
-       }
-
-       private static Bundle findThemeBundle(BundleContext bundleContext, String themeId) {
-               if (themeId == null)
-                       return null;
-               // TODO optimize
-               // TODO deal with multiple versions
-               Bundle themeBundle = null;
-               if (themeId != null) {
-                       for (Bundle bundle : bundleContext.getBundles())
-                               if (themeId.equals(bundle.getSymbolicName())) {
-                                       themeBundle = bundle;
-                                       break;
-                               }
-               }
-               return themeBundle;
-       }
-
-       class CmsExceptionHandler implements ExceptionHandler {
-
-               @Override
-               public void handleException(Throwable throwable) {
-                       // TODO be smarter
-                       CmsUiUtils.getCmsView().exception(throwable);
-               }
-
-       }
-
-       private class CmsEntryPointFactory implements EntryPointFactory {
-               private final CmsUiProvider page;
-               private final Repository repository;
-               private final String workspace;
-               private final Map<String, String> properties;
-
-               public CmsEntryPointFactory(CmsUiProvider page, Repository repository, String workspace,
-                               Map<String, String> properties) {
-                       this.page = page;
-                       this.repository = repository;
-                       this.workspace = workspace;
-                       this.properties = properties;
-               }
-
-               @Override
-               public EntryPoint create() {
-                       SimpleErgonomics entryPoint = new SimpleErgonomics(repository, workspace, jcrBasePath, page, properties) {
-                               private static final long serialVersionUID = -637940404865527290L;
-
-                               @Override
-                               protected void createAdminArea(Composite parent) {
-                                       Composite adminArea = new Composite(parent, SWT.NONE);
-                                       adminArea.setLayout(new FillLayout());
-                                       Button refresh = new Button(adminArea, SWT.PUSH);
-                                       refresh.setText("Reload App");
-                                       refresh.addSelectionListener(new SelectionAdapter() {
-                                               private static final long serialVersionUID = -7671999525536351366L;
-
-                                               @Override
-                                               public void widgetSelected(SelectionEvent e) {
-                                                       long timeBeforeReload = 1000;
-                                                       RWT.getClient().getService(JavaScriptExecutor.class).execute(
-                                                                       "setTimeout(function() { " + "location.reload();" + "}," + timeBeforeReload + ");");
-                                                       reloadApp();
-                                               }
-                                       });
-                               }
-                       };
-                       // entryPoint.setState("");
-                       entryPoint.setHeader(header);
-                       entryPoint.setHeaderHeight(headerHeight);
-                       // CmsSession.current.set(entryPoint);
-                       return entryPoint;
-               }
-
-               private void reloadApp() {
-                       new Thread("Refresh app") {
-                               @Override
-                               public void run() {
-                                       unregister();
-                                       register();
-                               }
-                       }.start();
-               }
-       }
-
-       private static ResourceLoader createResourceLoader(final String resourceName) {
-               return new ResourceLoader() {
-                       public InputStream getResourceAsStream(String resourceName) throws IOException {
-                               return getClass().getClassLoader().getResourceAsStream(resourceName);
-                       }
-               };
-       }
-
-       // private static ResourceLoader createUrlResourceLoader(final URL url) {
-       // return new ResourceLoader() {
-       // public InputStream getResourceAsStream(String resourceName)
-       // throws IOException {
-       // return url.openStream();
-       // }
-       // };
-       // }
-
-       /*
-        * TEXTS
-        */
-       private static String DEFAULT_LOADING_BODY = "<div"
-                       + " style=\"position: absolute; left: 50%; top: 50%; margin: -32px -32px; width: 64px; height:64px\">"
-                       + "<img src=\"./rwt-resources/" + LOADING_IMAGE
-                       + "\" width=\"32\" height=\"32\" style=\"margin: 16px 16px\"/>" + "</div>";
-}
diff --git a/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/SimpleErgonomics.java b/swt/rap/org.argeo.cms.swt.rap/src/org/argeo/cms/web/SimpleErgonomics.java
deleted file mode 100644 (file)
index 783f6eb..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-package org.argeo.cms.web;
-
-import java.util.Map;
-import java.util.UUID;
-
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.ux.CmsImageManager;
-import org.argeo.api.cms.ux.UxContext;
-import org.argeo.cms.swt.CmsException;
-import org.argeo.cms.swt.CmsStyles;
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.SimpleSwtUxContext;
-import org.argeo.cms.ui.CmsUiProvider;
-import org.argeo.cms.ui.util.DefaultImageManager;
-import org.argeo.cms.ui.util.SystemNotifications;
-import org.eclipse.rap.rwt.RWT;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.FillLayout;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
-/** Simple header/body ergonomics. */
-@Deprecated
-public class SimpleErgonomics extends AbstractCmsEntryPoint {
-       private static final long serialVersionUID = 8743413921359548523L;
-
-       private final static CmsLog log = CmsLog.getLog(SimpleErgonomics.class);
-
-       private boolean uiInitialized = false;
-       private Composite headerArea;
-       private Composite leftArea;
-       private Composite rightArea;
-       private Composite footerArea;
-       private Composite bodyArea;
-       private final CmsUiProvider uiProvider;
-
-       private CmsUiProvider header;
-       private Integer headerHeight = 0;
-       private Integer footerHeight = 0;
-       private CmsUiProvider lead;
-       private CmsUiProvider end;
-       private CmsUiProvider footer;
-
-       private CmsImageManager imageManager = new DefaultImageManager();
-       private UxContext uxContext = null;
-       private String uid;
-
-       public SimpleErgonomics(Repository repository, String workspace, String defaultPath, CmsUiProvider uiProvider,
-                       Map<String, String> factoryProperties) {
-               super(repository, workspace, defaultPath, factoryProperties);
-               this.uiProvider = uiProvider;
-       }
-
-       @Override
-       protected void initUi(Composite parent) {
-               uid = UUID.randomUUID().toString();
-               parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               parent.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(3, false)));
-
-               uxContext = new SimpleSwtUxContext();
-               if (!getUxContext().isMasterData())
-                       createAdminArea(parent);
-               headerArea = new Composite(parent, SWT.NONE);
-               headerArea.setLayout(new FillLayout());
-               GridData headerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
-               headerData.heightHint = headerHeight;
-               headerArea.setLayoutData(headerData);
-
-               // TODO: bi-directional
-               leftArea = new Composite(parent, SWT.NONE);
-               leftArea.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
-               leftArea.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
-               bodyArea = new Composite(parent, SWT.NONE);
-               bodyArea.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_BODY);
-               bodyArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
-               bodyArea.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
-               // TODO: bi-directional
-               rightArea = new Composite(parent, SWT.NONE);
-               rightArea.setLayoutData(new GridData(SWT.END, SWT.TOP, false, false));
-               rightArea.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
-               footerArea = new Composite(parent, SWT.NONE);
-               // footerArea.setLayout(new FillLayout());
-               GridData footerData = new GridData(SWT.FILL, SWT.FILL, false, false, 3, 1);
-               footerData.heightHint = footerHeight;
-               footerArea.setLayoutData(footerData);
-
-               uiInitialized = true;
-               refresh();
-       }
-
-       @Override
-       protected void refresh() {
-               if (!uiInitialized)
-                       return;
-               if (getState() == null)
-                       setState("");
-               refreshSides();
-               refreshBody();
-               if (log.isTraceEnabled())
-                       log.trace("UI refreshed " + getNode());
-       }
-
-       protected void createAdminArea(Composite parent) {
-       }
-
-       @Deprecated
-       protected void refreshHeader() {
-               if (header == null)
-                       return;
-
-               for (Control child : headerArea.getChildren())
-                       child.dispose();
-               try {
-                       header.createUi(headerArea, getNode());
-               } catch (RepositoryException e) {
-                       throw new CmsException("Cannot refresh header", e);
-               }
-               headerArea.layout(true, true);
-       }
-
-       protected void refreshSides() {
-               refresh(headerArea, header, CmsStyles.CMS_HEADER);
-               refresh(leftArea, lead, CmsStyles.CMS_LEAD);
-               refresh(rightArea, end, CmsStyles.CMS_END);
-               refresh(footerArea, footer, CmsStyles.CMS_FOOTER);
-       }
-
-       private void refresh(Composite area, CmsUiProvider uiProvider, String style) {
-               if (uiProvider == null)
-                       return;
-
-               for (Control child : area.getChildren())
-                       child.dispose();
-               CmsSwtUtils.style(area, style);
-               try {
-                       uiProvider.createUi(area, getNode());
-               } catch (RepositoryException e) {
-                       throw new CmsException("Cannot refresh header", e);
-               }
-               area.layout(true, true);
-       }
-
-       protected void refreshBody() {
-               // Exception
-               Throwable exception = getException();
-               if (exception != null) {
-                       SystemNotifications systemNotifications = new SystemNotifications(bodyArea);
-                       systemNotifications.notifyException(exception);
-                       resetException();
-                       return;
-                       // TODO report
-               }
-
-               // clear
-               for (Control child : bodyArea.getChildren())
-                       child.dispose();
-               bodyArea.setLayout(CmsSwtUtils.noSpaceGridLayout());
-
-               try {
-                       Node node = getNode();
-//                     if (node == null)
-//                             log.error("Context cannot be null");
-//                     else
-                       uiProvider.createUi(bodyArea, node);
-               } catch (RepositoryException e) {
-                       throw new CmsException("Cannot refresh body", e);
-               }
-
-               bodyArea.layout(true, true);
-       }
-
-       @Override
-       public UxContext getUxContext() {
-               return uxContext;
-       }
-       @Override
-       public String getUid() {
-               return uid;
-       }
-
-       public CmsImageManager getImageManager() {
-               return imageManager;
-       }
-
-       public void setHeader(CmsUiProvider header) {
-               this.header = header;
-       }
-
-       public void setHeaderHeight(Integer headerHeight) {
-               this.headerHeight = headerHeight;
-       }
-
-       public void setImageManager(CmsImageManager imageManager) {
-               this.imageManager = imageManager;
-       }
-
-       public CmsUiProvider getLead() {
-               return lead;
-       }
-
-       public void setLead(CmsUiProvider lead) {
-               this.lead = lead;
-       }
-
-       public CmsUiProvider getEnd() {
-               return end;
-       }
-
-       public void setEnd(CmsUiProvider end) {
-               this.end = end;
-       }
-
-       public CmsUiProvider getFooter() {
-               return footer;
-       }
-
-       public void setFooter(CmsUiProvider footer) {
-               this.footer = footer;
-       }
-
-       public CmsUiProvider getHeader() {
-               return header;
-       }
-
-       public void setFooterHeight(Integer footerHeight) {
-               this.footerHeight = footerHeight;
-       }
-
-}