+ add repository description
authorBruno Sinou <bsinou@argeo.org>
Fri, 8 Mar 2013 14:44:40 +0000 (14:44 +0000)
committerBruno Sinou <bsinou@argeo.org>
Fri, 8 Mar 2013 14:44:40 +0000 (14:44 +0000)
+ enhance distribution browser view
+ add a command to publish a repository

git-svn-id: https://svn.argeo.org/slc/trunk@6112 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

13 files changed:
plugins/org.argeo.slc.client.ui.dist/icons/discovery.gif [deleted file]
plugins/org.argeo.slc.client.ui.dist/icons/normalize.gif [new file with mode: 0644]
plugins/org.argeo.slc.client.ui.dist/plugin.xml
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/DistImages.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/DeleteWorkspace.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/NormalizeDistribution.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/PublishWorkspace.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/RegisterRepository.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/UnregisterRemoteRepo.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/BundleDetailsPage.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/DistributionEditorInput.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/DistributionOverviewPage.java
plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/views/DistributionsView.java

diff --git a/plugins/org.argeo.slc.client.ui.dist/icons/discovery.gif b/plugins/org.argeo.slc.client.ui.dist/icons/discovery.gif
deleted file mode 100644 (file)
index ec6cca4..0000000
Binary files a/plugins/org.argeo.slc.client.ui.dist/icons/discovery.gif and /dev/null differ
diff --git a/plugins/org.argeo.slc.client.ui.dist/icons/normalize.gif b/plugins/org.argeo.slc.client.ui.dist/icons/normalize.gif
new file mode 100644 (file)
index 0000000..b8ca14a
Binary files /dev/null and b/plugins/org.argeo.slc.client.ui.dist/icons/normalize.gif differ
index f801a997d28a2858a982bdca13e79c3b345cd343..dfad06fe23b8c2d34c6e4d8f9f16960ea493e432 100644 (file)
             id="org.argeo.slc.client.ui.dist.refreshArtifactBrowser"
             name="Refresh Artifact Browser">
        </command>
-               <command
+       <command
+            defaultHandler="org.argeo.slc.client.ui.dist.commands.PublishWorkspace"
+            id="org.argeo.slc.client.ui.dist.publishWorkspace"
+            name="Publish selected workspace">
+       </command>
+       <command
             defaultHandler="org.argeo.slc.client.ui.dist.commands.ShowSizeColumn"
             id="org.argeo.slc.client.ui.dist.showSizeColumn"
             name="Show size column">
index d2756ff8a3fee9bef318eca022a694c65e99946b..cd9b229f67544b733fa3abc29b6bc434d0dd6580 100644 (file)
@@ -34,6 +34,8 @@ public class DistImages {
        /* REPOSITORIES */
        public final static Image IMG_REPO = DistPlugin.getImageDescriptor(
                        "icons/repo.gif").createImage();
+       public final static Image IMG_HOME_REPO = DistPlugin.getImageDescriptor(
+                       "icons/homeRepo.gif").createImage();
        public final static Image IMG_REPO_READONLY = DistPlugin
                        .getImageDescriptor("icons/repoReadOnly.gif").createImage();
        public final static Image IMG_ADD_REPO = DistPlugin.getImageDescriptor(
@@ -43,6 +45,13 @@ public class DistImages {
        public final static Image IMG_FETCH_REPO = DistPlugin.getImageDescriptor(
                        "icons/fetchRepo.png").createImage();
 
+       /* DISTRIBUTIONS */
+       public final static Image IMG_DISTGRP = DistPlugin.getImageDescriptor(
+                       "icons/distGrp.gif").createImage();
+       public final static Image IMG_DISTGRP_READONLY = DistPlugin
+                       .getImageDescriptor("icons/distGrpReadOnly.gif").createImage();
+       
+       
        /* CHECK BOXES */
        public final static Image CHECKED = DistPlugin.getImageDescriptor(
                        "icons/checked.gif").createImage();
index 676a921c02bc503ea980c9ab68d87269f1d82074..b4982a58e17d8a84e7555b7e11b5ce168c75701a 100644 (file)
@@ -41,7 +41,7 @@ public class DeleteWorkspace extends AbstractHandler {
        public final static String ID = DistPlugin.ID + ".deleteWorkspace";
        public final static String PARAM_WORKSPACE_NAME = DistPlugin.ID
                        + ".workspaceName";
-       public final static String DEFAULT_LABEL = "Delete";
+       public final static String DEFAULT_LABEL = "Clear";
        public final static String DEFAULT_ICON_PATH = "icons/removeItem.gif";
 
        /* DEPENDENCY INJECTION */
index 159f5faa26f7629d09064655b03f7379d4b30da3..433d7b67f29b0d876e22cb917fe3378c08f1a8fc 100644 (file)
@@ -71,8 +71,8 @@ import org.sonatype.aether.util.artifact.DefaultArtifact;
 public class NormalizeDistribution extends AbstractHandler implements SlcNames {
        public final static String ID = DistPlugin.ID + ".normalizeDistribution";
        public final static String PARAM_WORKSPACE = "workspace";
-       public final static String DEFAULT_LABEL = "Normalize";
-       public final static String DEFAULT_ICON_PATH = "icons/addItem.gif";
+       public final static String DEFAULT_LABEL = "Normalize...";
+       public final static String DEFAULT_ICON_PATH = "icons/normalize.gif";
 
        private final static Log log = LogFactory
                        .getLog(NormalizeDistribution.class);
@@ -336,7 +336,7 @@ public class NormalizeDistribution extends AbstractHandler implements SlcNames {
 
                protected void configureShell(Shell shell) {
                        super.configureShell(shell);
-                       shell.setText("Configure Normalization");
+                       shell.setText("Normalize...");
                }
 
                public String getVersion() {
diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/PublishWorkspace.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/PublishWorkspace.java
new file mode 100644 (file)
index 0000000..59d34fe
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.slc.client.ui.dist.commands;
+
+import javax.jcr.Credentials;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.Privilege;
+
+import org.argeo.ArgeoException;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.slc.client.ui.dist.DistPlugin;
+import org.argeo.slc.client.ui.dist.views.DistributionsView;
+import org.argeo.slc.client.ui.dist.views.DistributionsView.DistributionViewSelectedElement;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * Publish the current workspace by giving REOD_ONLY rights to anonymous.
+ */
+
+public class PublishWorkspace extends AbstractHandler {
+       // private static final Log log = LogFactory.getLog(PublishWorkspace.class);
+       public final static String ID = DistPlugin.ID + ".publishWorkspace";
+       public final static String DEFAULT_LABEL = "Publish workspace";
+       public final static String DEFAULT_ICON_PATH = "icons/publish.gif";
+
+       private String publicRole = "anonymous";
+
+       private String workspaceName;
+       private Repository repository;
+       private Credentials credentials;
+
+       public Object execute(ExecutionEvent event) throws ExecutionException {
+               IWorkbenchWindow iww = DistPlugin.getDefault().getWorkbench()
+                               .getActiveWorkbenchWindow();
+               IWorkbenchPart view = iww.getActivePage().getActivePart();
+               if (view instanceof DistributionsView) {
+                       DistributionViewSelectedElement dvse = ((DistributionsView) view)
+                                       .getSelectedElement();
+                       if (dvse != null && dvse.isWorkspace) {
+                               repository = dvse.repository;
+                               credentials = dvse.credentials;
+                               workspaceName = dvse.wkspName;
+                       }
+               }
+
+               if (repository != null && workspaceName != null) {
+                       String msg = "Are you sure you want to publish this distribution: "
+                                       + workspaceName + " ?";
+                       boolean result = MessageDialog.openConfirm(DistPlugin.getDefault()
+                                       .getWorkbench().getDisplay().getActiveShell(),
+                                       "Confirm publication", msg);
+
+                       if (result) {
+
+                               Session session = null;
+                               try {
+                                       session = repository.login(credentials, workspaceName);
+                                       JcrUtils.addPrivilege(session, "/", publicRole,
+                                                       Privilege.JCR_READ);
+                                       JcrUtils.logoutQuietly(session);
+                                       // CommandHelpers.callCommand(RefreshDistributionsView.ID);
+                               } catch (RepositoryException re) {
+                                       throw new ArgeoException(
+                                                       "Unexpected error while publishing workspace "
+                                                                       + workspaceName, re);
+                               } finally {
+                                       JcrUtils.logoutQuietly(session);
+                               }
+                       }
+               }
+               return null;
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+       public void setWorkspaceName(String workspaceName) {
+               this.workspaceName = workspaceName;
+       }
+}
\ No newline at end of file
index 805257a121662ca2508fe4a8540f7bdc07494ec6..a87e498b9640599490796c4d540681e349d27c9b 100644 (file)
@@ -38,7 +38,7 @@ public class RegisterRepository extends AbstractHandler implements ArgeoNames,
                SlcNames {
 
        public final static String ID = DistPlugin.ID + ".registerRepository";
-       public final static String DEFAULT_LABEL = "Register a repository";
+       public final static String DEFAULT_LABEL = "Register a repository...";
        public final static String DEFAULT_ICON_PATH = "icons/addRepo.gif";
 
        /* DEPENDENCY INJECTION */
index 1dfe9139b661ad07259f035347e5f0598db1681f..882e2cdf56d07034473d958e87539825d0d544d2 100644 (file)
@@ -40,7 +40,7 @@ public class UnregisterRemoteRepo extends AbstractHandler {
        // private static final Log log = LogFactory
        // .getLog(UnregisterRemoteRepo.class);
        public final static String ID = DistPlugin.ID + ".unregisterRemoteRepo";
-       public final static String DEFAULT_LABEL = "Unregister repository";
+       public final static String DEFAULT_LABEL = "Unregister this repository";
        public final static String DEFAULT_ICON_PATH = "icons/removeItem.gif";
        public final static String PARAM_REPO_PATH = DistPlugin.ID
                        + ".repoNodePath";
index b0f2fa6c52b5f497d824542bfd2d84a8e4f89fef..269466083b12240c64b6d559d859d506d3b11edb 100644 (file)
@@ -15,7 +15,6 @@
  */
 package org.argeo.slc.client.ui.dist.editors;
 
-import java.net.URL;
 import java.util.List;
 
 import javax.jcr.Node;
@@ -34,7 +33,6 @@ import org.argeo.eclipse.ui.ErrorFeedback;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.slc.SlcException;
 import org.argeo.slc.client.ui.dist.DistConstants;
-import org.argeo.slc.client.ui.dist.utils.AbstractHyperlinkListener;
 import org.argeo.slc.jcr.SlcNames;
 import org.argeo.slc.jcr.SlcTypes;
 import org.eclipse.jface.viewers.ColumnLabelProvider;
@@ -54,15 +52,10 @@ import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.Text;
 import org.eclipse.swt.widgets.Tree;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.browser.IWebBrowser;
-import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
 import org.eclipse.ui.forms.IManagedForm;
 import org.eclipse.ui.forms.editor.FormEditor;
 import org.eclipse.ui.forms.editor.FormPage;
-import org.eclipse.ui.forms.events.HyperlinkEvent;
 import org.eclipse.ui.forms.widgets.FormToolkit;
-import org.eclipse.ui.forms.widgets.Hyperlink;
 import org.eclipse.ui.forms.widgets.ScrolledForm;
 import org.eclipse.ui.forms.widgets.Section;
 
@@ -122,7 +115,7 @@ public class BundleDetailsPage extends FormPage implements SlcNames, SlcTypes {
                createField(details, "Symbolic name", SlcNames.SLC_SYMBOLIC_NAME);
                createField(details, "Version", SlcNames.SLC_BUNDLE_VERSION);
                createField(details, "Group Id", SlcNames.SLC_GROUP_ID);
-               createHyperlink(details, "Licence", DistConstants.SLC_BUNDLE_LICENCE);
+               //createHyperlink(details, "Licence", DistConstants.SLC_BUNDLE_LICENCE);
                createField(details, "Vendor", DistConstants.SLC_BUNDLE_VENDOR);
 
        }
@@ -405,34 +398,34 @@ public class BundleDetailsPage extends FormPage implements SlcNames, SlcTypes {
                return section;
        }
 
-       private void createHyperlink(Composite parent, String label,
-                       String jcrPropName) throws RepositoryException {
-               toolkit.createLabel(parent, label, SWT.NONE);
-               if (currBundle.hasProperty(jcrPropName)) {
-                       final Hyperlink link = toolkit.createHyperlink(parent, currBundle
-                                       .getProperty(jcrPropName).getString(), SWT.NONE);
-                       link.addHyperlinkListener(new AbstractHyperlinkListener() {
-                               @Override
-                               public void linkActivated(HyperlinkEvent e) {
-                                       try {
-                                               IWorkbenchBrowserSupport browserSupport = PlatformUI
-                                                               .getWorkbench().getBrowserSupport();
-                                               IWebBrowser browser = browserSupport
-                                                               .createBrowser(
-                                                                               IWorkbenchBrowserSupport.LOCATION_BAR
-                                                                                               | IWorkbenchBrowserSupport.NAVIGATION_BAR,
-                                                                               "SLC Distribution browser",
-                                                                               "SLC Distribution browser",
-                                                                               "A tool tip");
-                                               browser.openURL(new URL(link.getText()));
-                                       } catch (Exception ex) {
-                                               throw new SlcException("error opening browser", ex); //$NON-NLS-1$
-                                       }
-                               }
-                       });
-               } else
-                       toolkit.createLabel(parent, "", SWT.NONE);
-       }
+       // private void createHyperlink(Composite parent, String label,
+       // String jcrPropName) throws RepositoryException {
+       // toolkit.createLabel(parent, label, SWT.NONE);
+       // if (currBundle.hasProperty(jcrPropName)) {
+       // final Hyperlink link = toolkit.createHyperlink(parent, currBundle
+       // .getProperty(jcrPropName).getString(), SWT.NONE);
+       // link.addHyperlinkListener(new AbstractHyperlinkListener() {
+       // @Override
+       // public void linkActivated(HyperlinkEvent e) {
+       // try {
+       // IWorkbenchBrowserSupport browserSupport = PlatformUI
+       // .getWorkbench().getBrowserSupport();
+       // IWebBrowser browser = browserSupport
+       // .createBrowser(
+       // IWorkbenchBrowserSupport.LOCATION_BAR
+       // | IWorkbenchBrowserSupport.NAVIGATION_BAR,
+       // "SLC Distribution browser",
+       // "SLC Distribution browser",
+       // "A tool tip");
+       // browser.openURL(new URL(link.getText()));
+       // } catch (Exception ex) {
+       //                                              throw new SlcException("error opening browser", ex); //$NON-NLS-1$
+       // }
+       // }
+       // });
+       // } else
+       // toolkit.createLabel(parent, "", SWT.NONE);
+       // }
 
        /** Creates a text area with corresponding maven snippet */
        private void createMavenSnipet(Composite parent) {
index 3663827e3113669198e49f703596ae53362c0a1e..d0f27dd89693171925c6f3d30bd273d9773c531e 100644 (file)
@@ -30,25 +30,28 @@ import org.eclipse.ui.IPersistableElement;
 public class DistributionEditorInput implements IEditorInput, SlcNames {
 
        private String repositoryName;
+       private String repositoryDescription;
        private Repository repository;
        private String workspaceName;
        private String artifactsBase = RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH;
        private Credentials credentials;
 
        public DistributionEditorInput(String repositoryName,
-                       Repository repository, String workspaceName, String artifactsBase,
-                       Credentials credentials) {
+                       String repositoryDescription, Repository repository,
+                       String workspaceName, String artifactsBase, Credentials credentials) {
                super();
                this.repository = repository;
                this.repositoryName = repositoryName;
+               this.repositoryDescription = repositoryDescription;
                this.workspaceName = workspaceName;
                this.artifactsBase = artifactsBase;
                this.credentials = credentials;
        }
 
        public DistributionEditorInput(String repositoryName,
-                       Repository repository, String workspaceName, Credentials credentials) {
-               this(repositoryName, repository, workspaceName,
+                       String repositoryDescription, Repository repository,
+                       String workspaceName, Credentials credentials) {
+               this(repositoryName, repositoryDescription, repository, workspaceName,
                                RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH, credentials);
        }
 
@@ -106,6 +109,10 @@ public class DistributionEditorInput implements IEditorInput, SlcNames {
                return repositoryName;
        }
 
+       public String getRepositoryDescription() {
+               return repositoryDescription;
+       }
+
        public Credentials getCredentials() {
                return credentials;
        }
index 4468cc9194f8e2cbbedee13f9818a44e8ce38a7c..eb14ae8cbf2cf5fc89e12ed10e1aa0271660fdad 100644 (file)
@@ -209,9 +209,10 @@ public class DistributionOverviewPage extends FormPage implements SlcNames {
                GridData gd = new GridData(SWT.FILL, SWT.FILL, false, false);
                header.setLayoutData(gd);
 
-               // TODO display real repository information
                // Title: some meta information
-               Label lbl = tk.createLabel(header, "Current repository: ", SWT.NONE);
+               String desc = ((DistributionEditorInput) getEditorInput())
+                               .getRepositoryDescription();
+               Label lbl = tk.createLabel(header, desc, SWT.NONE);
 
                gd = new GridData(SWT.FILL, SWT.FILL, false, false);
                gd.horizontalSpan = 2;
index 26e38f1bbbebfdbefd0cc38a4fd945bc809e294f..09d3fa70148bd52c2c1ea6744cdd65844225821f 100644 (file)
@@ -51,8 +51,8 @@ import org.argeo.slc.client.ui.dist.commands.CopyWorkspace;
 import org.argeo.slc.client.ui.dist.commands.CreateWorkspace;
 import org.argeo.slc.client.ui.dist.commands.DeleteWorkspace;
 import org.argeo.slc.client.ui.dist.commands.Fetch;
-import org.argeo.slc.client.ui.dist.commands.ManageWorkspaceAuth;
 import org.argeo.slc.client.ui.dist.commands.NormalizeDistribution;
+import org.argeo.slc.client.ui.dist.commands.PublishWorkspace;
 import org.argeo.slc.client.ui.dist.commands.RegisterRepository;
 import org.argeo.slc.client.ui.dist.commands.UnregisterRemoteRepo;
 import org.argeo.slc.client.ui.dist.editors.DistributionEditor;
@@ -116,22 +116,36 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                                | SWT.FULL_SELECTION | SWT.BORDER);
 
                TreeViewerColumn col = new TreeViewerColumn(viewer, SWT.NONE);
-               col.getColumn().setWidth(200);
+               col.getColumn().setWidth(400);
                col.setLabelProvider(new ColumnLabelProvider() {
                        @Override
                        public String getText(Object element) {
-                               if (element instanceof RepoElem)
-                                       return ((RepoElem) element).getLabel();
-                               return element.toString();
+                               if (element instanceof BrowserElem)
+                                       return ((BrowserElem) element).getLabel();
+                               else
+                                       return element.toString();
                        }
 
                        @Override
                        public Image getImage(Object element) {
-                               if (element instanceof RepoElem)
-                                       return DistImages.IMG_REPO;
-                               else if (element instanceof DistributionElem) {
+                               if (element instanceof BrowserElem) {
+                                       BrowserElem bElement = (BrowserElem) element;
+                                       if (bElement instanceof RepoElem) {
+                                               if (bElement.isHomeRepo())
+                                                       return DistImages.IMG_HOME_REPO;
+                                               else if (bElement.isReadOnly)
+                                                       return DistImages.IMG_REPO_READONLY;
+                                               else
+                                                       return DistImages.IMG_REPO;
+
+                                       } else if (bElement instanceof DistribGroupElem) {
+                                               if (bElement.isReadOnly)
+                                                       return DistImages.IMG_DISTGRP_READONLY;
+                                               else
+                                                       return DistImages.IMG_DISTGRP;
+                                       }
+                               } else if (element instanceof DistributionElem)
                                        return DistImages.IMG_WKSP;
-                               }
                                return null;
                        }
                });
@@ -142,7 +156,7 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
 
                viewer.setContentProvider(new DistributionsContentProvider());
                viewer.addDoubleClickListener(new DistributionsDCL());
-               viewer.setComparator(new ArtifactNamesComparator());
+               viewer.setComparator(new BrowserElementComparator());
 
                // Enable selection retrieving from outside the view
                getSite().setSelectionProvider(viewer);
@@ -201,102 +215,173 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
        protected void contextMenuAboutToShow(IMenuManager menuManager) {
                IWorkbenchWindow window = DistPlugin.getDefault().getWorkbench()
                                .getActiveWorkbenchWindow();
-               try {
-                       // Most of the implemented commands support only one selected
-                       // element
-                       boolean singleElement = ((IStructuredSelection) viewer
-                                       .getSelection()).size() == 1;
-                       // Get Current selected item :
-                       Object firstElement = ((IStructuredSelection) viewer.getSelection())
-                                       .getFirstElement();
+               // Most of the implemented commands support only one selected
+               // element
+               boolean singleElement = ((IStructuredSelection) viewer.getSelection())
+                               .size() == 1;
+               // Get Current selected item :
+               Object firstElement = ((IStructuredSelection) viewer.getSelection())
+                               .getFirstElement();
+
+               if (firstElement instanceof TreeParent
+                               || firstElement instanceof BrowserElem) {
+                       String wsName = null;
+                       String targetRepoPath = null;
+
+                       // Build conditions depending on element type
+                       boolean isDistribElem = false, isRepoElem = false;
+                       boolean isHomeRepo = false, isReadOnly = true;
+
+                       if (firstElement instanceof DistributionElem) {
+                               DistributionElem de = (DistributionElem) firstElement;
+                               isDistribElem = true;
+                               wsName = de.getName();
+                               isReadOnly = de.isReadOnly();
+                       } else if (firstElement instanceof RepoElem) {
+                               RepoElem re = (RepoElem) firstElement;
+                               isRepoElem = true;
+                               targetRepoPath = re.getRepoPath();
+                               isHomeRepo = re.isHomeRepo();
+                               isReadOnly = re.isReadOnly();
+                       }
 
-                       if (firstElement instanceof TreeParent
-                                       || firstElement instanceof RepoElem) {
-                               String wsName = null;
-                               String targetRepoPath = null;
+                       // create workspace
+                       CommandHelpers.refreshCommand(menuManager, window,
+                                       CreateWorkspace.ID, CreateWorkspace.DEFAULT_LABEL,
+                                       CreateWorkspace.DEFAULT_ICON_PATH, isRepoElem
+                                                       && singleElement && !isReadOnly);
+                       // publish workspace
+                       CommandHelpers.refreshCommand(menuManager, window,
+                                       PublishWorkspace.ID, PublishWorkspace.DEFAULT_LABEL,
+                                       PublishWorkspace.DEFAULT_ICON_PATH, isDistribElem
+                                                       && singleElement && !isReadOnly);
+
+                       // Register a remote repository
+                       CommandHelpers.refreshCommand(menuManager, window,
+                                       RegisterRepository.ID, RegisterRepository.DEFAULT_LABEL,
+                                       RegisterRepository.DEFAULT_ICON_PATH, isRepoElem
+                                                       && singleElement);
+
+                       // Unregister a remote repository
+                       Map<String, String> params = new HashMap<String, String>();
+                       params.put(UnregisterRemoteRepo.PARAM_REPO_PATH, targetRepoPath);
+                       CommandHelpers.refreshParameterizedCommand(menuManager, window,
+                                       UnregisterRemoteRepo.ID,
+                                       UnregisterRemoteRepo.DEFAULT_LABEL,
+                                       UnregisterRemoteRepo.DEFAULT_ICON_PATH, isRepoElem
+                                                       && !isHomeRepo && singleElement, params);
+
+                       // Fetch repository
+                       params = new HashMap<String, String>();
+                       params.put(Fetch.PARAM_TARGET_REPO, targetRepoPath);
+                       CommandHelpers.refreshParameterizedCommand(menuManager, window,
+                                       Fetch.ID, Fetch.DEFAULT_LABEL, Fetch.DEFAULT_ICON_PATH,
+                                       !isDistribElem && singleElement && !isReadOnly, params);
+
+                       // Normalize workspace
+                       params = new HashMap<String, String>();
+                       params.put(NormalizeDistribution.PARAM_WORKSPACE, wsName);
+                       CommandHelpers.refreshParameterizedCommand(menuManager, window,
+                                       NormalizeDistribution.ID,
+                                       NormalizeDistribution.DEFAULT_LABEL,
+                                       NormalizeDistribution.DEFAULT_ICON_PATH, isDistribElem
+                                                       && singleElement && !isReadOnly, params);
+
+                       // Copy workspace
+                       params = new HashMap<String, String>();
+                       params.put(CopyWorkspace.PARAM_WORKSPACE_NAME, wsName);
+                       CommandHelpers.refreshParameterizedCommand(menuManager, window,
+                                       CopyWorkspace.ID, CopyWorkspace.DEFAULT_LABEL,
+                                       CopyWorkspace.DEFAULT_ICON_PATH, isDistribElem
+                                                       && singleElement, params);
+
+                       // Clear Workspace
+                       params = new HashMap<String, String>();
+                       params.put(DeleteWorkspace.PARAM_WORKSPACE_NAME, wsName);
+                       CommandHelpers.refreshParameterizedCommand(menuManager, window,
+                                       DeleteWorkspace.ID, DeleteWorkspace.DEFAULT_LABEL,
+                                       DeleteWorkspace.DEFAULT_ICON_PATH, isDistribElem
+                                                       && singleElement && !isReadOnly, params);
+
+                       // // Manage workspace authorizations
+                       // params = new HashMap<String, String>();
+                       // params.put(ManageWorkspaceAuth.PARAM_WORKSPACE_NAME, wsName);
+                       // CommandHelpers.refreshParameterizedCommand(menuManager, window,
+                       // ManageWorkspaceAuth.ID, ManageWorkspaceAuth.DEFAULT_LABEL,
+                       // ManageWorkspaceAuth.DEFAULT_ICON_PATH, isDistribElem
+                       // && singleElement && !isReadOnly, params);
+               }
+               // } catch (RepositoryException e) {
+               // throw new SlcException("unexpected errror while "
+               // + "building context menu", e);
+               // }
+       }
 
-                               // Build conditions depending on element type (repo or
-                               // distribution
-                               // for the time being)
-                               boolean isDistribElem = false; // , isRepoElem = false;
+       /**
+        * Exposes some Repository and workspace information about the selected
+        * element without exposing the UI model
+        */
+       public class DistributionViewSelectedElement {
+               public boolean isRepository = false;
+               public boolean isWorkspaceGroup = false;
+               public boolean isWorkspace = false;
+               public String repositoryDescription;
+               public Node repoNode;
+               public String wkspName;
+               public String wkspPrefix;
+               public Repository repository;
+               public Credentials credentials;
+       }
 
-                               if (firstElement instanceof DistributionElem) {
-                                       isDistribElem = true;
-                                       wsName = ((DistributionElem) firstElement).getName();
-                               }
+       /**
+        * Returns a {@see DistributionViewSelectedElement} if one and only one
+        * valid element is currently selected.
+        * 
+        */
+       public DistributionViewSelectedElement getSelectedElement() {
 
-                               if (firstElement instanceof RepoElem) {
-                                       Node node = ((RepoElem) firstElement).getRepoNode();
-                                       targetRepoPath = node.getPath();
-                               }
+               IStructuredSelection iss = (IStructuredSelection) viewer.getSelection();
+               if (iss.isEmpty() || iss.size() > 1)
+                       return null;
 
-                               // create workspace
-                               CommandHelpers.refreshCommand(menuManager, window,
-                                               CreateWorkspace.ID, CreateWorkspace.DEFAULT_LABEL,
-                                               CreateWorkspace.DEFAULT_ICON_PATH, !isDistribElem
-                                                               && singleElement);
-
-                               // Register a remote repository
-                               CommandHelpers.refreshCommand(menuManager, window,
-                                               RegisterRepository.ID,
-                                               RegisterRepository.DEFAULT_LABEL,
-                                               RegisterRepository.DEFAULT_ICON_PATH, !isDistribElem
-                                                               && singleElement);
-
-                               // Unregister a remote repository
-                               Map<String, String> params = new HashMap<String, String>();
-                               params.put(UnregisterRemoteRepo.PARAM_REPO_PATH, targetRepoPath);
-                               CommandHelpers.refreshParameterizedCommand(menuManager, window,
-                                               UnregisterRemoteRepo.ID,
-                                               UnregisterRemoteRepo.DEFAULT_LABEL,
-                                               UnregisterRemoteRepo.DEFAULT_ICON_PATH, !isDistribElem
-                                                               && singleElement, params);
-
-                               // Fetch repository
-                               params = new HashMap<String, String>();
-                               params.put(Fetch.PARAM_TARGET_REPO, targetRepoPath);
-                               CommandHelpers.refreshParameterizedCommand(menuManager, window,
-                                               Fetch.ID, Fetch.DEFAULT_LABEL, Fetch.DEFAULT_ICON_PATH,
-                                               !isDistribElem && singleElement, params);
-
-                               // Normalize workspace
-                               params = new HashMap<String, String>();
-                               params.put(NormalizeDistribution.PARAM_WORKSPACE, wsName);
-                               CommandHelpers.refreshParameterizedCommand(menuManager, window,
-                                               NormalizeDistribution.ID,
-                                               NormalizeDistribution.DEFAULT_LABEL,
-                                               NormalizeDistribution.DEFAULT_ICON_PATH, isDistribElem
-                                                               && singleElement, params);
-
-                               // Copy workspace
-                               params = new HashMap<String, String>();
-                               params.put(CopyWorkspace.PARAM_WORKSPACE_NAME, wsName);
-                               CommandHelpers.refreshParameterizedCommand(menuManager, window,
-                                               CopyWorkspace.ID, CopyWorkspace.DEFAULT_LABEL,
-                                               CopyWorkspace.DEFAULT_ICON_PATH, isDistribElem
-                                                               && singleElement, params);
-
-                               // Delete Workspace
-                               params = new HashMap<String, String>();
-                               params.put(DeleteWorkspace.PARAM_WORKSPACE_NAME, wsName);
-                               CommandHelpers.refreshParameterizedCommand(menuManager, window,
-                                               DeleteWorkspace.ID, DeleteWorkspace.DEFAULT_LABEL,
-                                               DeleteWorkspace.DEFAULT_ICON_PATH, isDistribElem
-                                                               && singleElement, params);
-
-                               // Manage workspace authorizations
-                               params = new HashMap<String, String>();
-                               params.put(ManageWorkspaceAuth.PARAM_WORKSPACE_NAME, wsName);
-                               CommandHelpers.refreshParameterizedCommand(menuManager, window,
-                                               ManageWorkspaceAuth.ID,
-                                               ManageWorkspaceAuth.DEFAULT_LABEL,
-                                               ManageWorkspaceAuth.DEFAULT_ICON_PATH, isDistribElem
-                                                               && singleElement, params);
-                       }
-               } catch (RepositoryException e) {
-                       throw new SlcException("unexpected errror while "
-                                       + "building context menu", e);
-               }
+               DistributionViewSelectedElement dvse = new DistributionViewSelectedElement();
+               Object obj = iss.getFirstElement();
+               if (obj instanceof RepoElem) {
+                       RepoElem re = (RepoElem) obj;
+                       dvse.isRepository = true;
+                       dvse.repository = re.getRepository();
+                       dvse.repoNode = re.getRepoNode();
+                       dvse.credentials = re.getCredentials();
+                       dvse.repositoryDescription = getRepositoryDescription(re);
+               } else if (obj instanceof DistribGroupElem) {
+                       DistribGroupElem dge = (DistribGroupElem) obj;
+                       dvse.isWorkspaceGroup = true;
+                       dvse.repository = dge.getRepoElem().getRepository();
+                       dvse.repoNode = dge.getRepoElem().getRepoNode();
+                       dvse.credentials = dge.getRepoElem().getCredentials();
+                       dvse.wkspPrefix = dge.getLabel();
+                       dvse.repositoryDescription = getRepositoryDescription(dge
+                                       .getRepoElem());
+               } else if (obj instanceof DistributionElem) {
+                       DistributionElem de = (DistributionElem) obj;
+                       dvse.isWorkspace = true;
+                       dvse.repository = de.getRepoElem().getRepository();
+                       dvse.repoNode = de.getRepoElem().getRepoNode();
+                       dvse.credentials = de.getRepoElem().getCredentials();
+                       dvse.wkspName = de.getName();
+                       dvse.repositoryDescription = getRepositoryDescription(de
+                                       .getRepoElem());
+               }
+               return dvse;
+       }
+
+       private String getRepositoryDescription(RepoElem repo) {
+               StringBuffer repoDesc = new StringBuffer();
+               repoDesc.append(repo.getLabel());
+               repoDesc.append(" (");
+               repoDesc.append(JcrUtils.get(repo.getRepoNode(), ARGEO_URI));
+               repoDesc.append(")");
+               return repoDesc.toString();
        }
 
        @Override
@@ -332,7 +417,15 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                                while (repos.hasNext()) {
                                        Node repoNode = repos.nextNode();
                                        if (repoNode.isNodeType(ArgeoTypes.ARGEO_REMOTE_REPOSITORY)) {
-                                               repositories.add(new RepoElem(repoNode));
+                                               if (RepoConstants.DEFAULT_JAVA_REPOSITORY_ALIAS
+                                                               .equals(repoNode.getName()))
+                                                       repositories
+                                                                       .add(new RepoElem(repoNode, true, false));
+                                               else if (repoNode.hasNode(ARGEO_PASSWORD))
+                                                       repositories.add(new RepoElem(repoNode));
+                                               else
+                                                       repositories
+                                                                       .add(new RepoElem(repoNode, false, true));
                                        }
                                }
                        } catch (RepositoryException e) {
@@ -346,8 +439,8 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                }
 
                public Object[] getChildren(Object parentElement) {
-                       if (parentElement instanceof RepoElem) {
-                               return ((RepoElem) parentElement).getChildren();
+                       if (parentElement instanceof BrowserElem) {
+                               return ((BrowserElem) parentElement).getChildren();
                        } else if (parentElement instanceof DistributionElem) {
                                return ((DistributionElem) parentElement).getChildren();
                        }
@@ -360,7 +453,7 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                }
 
                public boolean hasChildren(Object element) {
-                       if (element instanceof RepoElem) {
+                       if (element instanceof BrowserElem) {
                                return true;
                        } else if (element instanceof DistributionElem) {
                                return false;
@@ -374,16 +467,60 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                        repositories = new ArrayList<RepoElem>();
                        JcrUtils.logoutQuietly(nodeSession);
                }
+       }
 
+       private class BrowserElementComparator extends ArtifactNamesComparator {
+               @Override
+               public int category(Object element) {
+                       // Home repository always first
+                       if (element instanceof RepoElem
+                                       && ((RepoElem) element).isHomeRepo())
+                               return 2;
+                       else
+                               return super.category(element);
+               }
+       }
+
+       /** Abstract class to simplify UI conditions build */
+       abstract class BrowserElem {
+               private boolean isHomeRepo = false;
+               private boolean isReadOnly = false;
+
+               public BrowserElem(boolean isHomeRepo, boolean isReadOnly) {
+                       this.isHomeRepo = isHomeRepo;
+                       this.isReadOnly = isReadOnly;
+               }
+
+               public BrowserElem() {
+               }
+
+               public abstract String getLabel();
+
+               public abstract Object[] getChildren();
+
+               public void dispose() {
+               }
+
+               public boolean isHomeRepo() {
+                       return isHomeRepo;
+               }
+
+               public boolean isReadOnly() {
+                       return isReadOnly;
+               }
        }
 
        /** A software repository */
-       private class RepoElem {
+       private class RepoElem extends BrowserElem {
                private Node repoNode;
-
                private Repository repository;
                private Credentials credentials;
 
+               public RepoElem(Node repoNode, boolean isHomeRepo, boolean isReadOnly) {
+                       super(isHomeRepo, isReadOnly);
+                       this.repoNode = repoNode;
+               }
+
                public RepoElem(Node repoNode) {
                        this.repoNode = repoNode;
                }
@@ -420,21 +557,26 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                                session = repository.login(credentials);
                                String[] workspaceNames = session.getWorkspace()
                                                .getAccessibleWorkspaceNames();
-                               List<DistributionElem> distributionElems = new ArrayList<DistributionElem>();
+                               // List<DistributionElem> distributionElems = new
+                               // ArrayList<DistributionElem>();
+                               Map<String, DistribGroupElem> children = new HashMap<String, DistributionsView.DistribGroupElem>();
                                for (String workspaceName : workspaceNames) {
                                        // filter technical workspaces
                                        // FIXME: rely on a more robust rule than just wksp name
                                        if (workspaceName.lastIndexOf('-') > 0) {
-                                               Node workspaceNode = repoNode.hasNode(workspaceName) ? repoNode
-                                                               .getNode(workspaceName) : repoNode
-                                                               .addNode(workspaceName);
+                                               String prefix = workspaceName.substring(0,
+                                                               workspaceName.lastIndexOf('-'));
+                                               if (!repoNode.hasNode(workspaceName))
+                                                       repoNode.addNode(workspaceName);
                                                repoNode.getSession().save();
-                                               distributionElems.add(new DistributionElem(this,
-                                                               workspaceNode));
+                                               if (!children.containsKey(prefix)) {
+                                                       children.put(prefix, new DistribGroupElem(
+                                                                       RepoElem.this, prefix));
+                                               }
                                                // FIXME remove deleted workspaces
                                        }
                                }
-                               return distributionElems.toArray();
+                               return children.values().toArray();
                        } catch (RepositoryException e) {
                                throw new SlcException(
                                                "Cannot list workspaces for " + repoNode, e);
@@ -443,13 +585,6 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                        }
                }
 
-               public void dispose() {
-               }
-
-               public Node getRepoNode() {
-                       return repoNode;
-               }
-
                public String getRepoPath() {
                        try {
                                return repoNode.getPath();
@@ -467,6 +602,68 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                        return credentials;
                }
 
+               public Node getRepoNode() {
+                       return repoNode;
+               }
+
+       }
+
+       /**
+        * Abstracts a group of distribution, that is a bunch of workspaces with
+        * same prefix.
+        */
+       private class DistribGroupElem extends BrowserElem {
+               private RepoElem repoElem;
+               private String name;
+
+               public DistribGroupElem(RepoElem repoElem, String prefix) {
+                       super(repoElem.isHomeRepo(), repoElem.isReadOnly());
+                       this.repoElem = repoElem;
+                       this.name = prefix;
+               }
+
+               public Object[] getChildren() {
+                       repoElem.connect();
+                       Session session = null;
+                       try {
+                               Repository repository = repoElem.getRepository();
+                               Node repoNode = repoElem.getRepoNode();
+                               session = repository.login(repoElem.getCredentials());
+
+                               String[] workspaceNames = session.getWorkspace()
+                                               .getAccessibleWorkspaceNames();
+                               List<DistributionElem> distributionElems = new ArrayList<DistributionElem>();
+                               for (String workspaceName : workspaceNames) {
+                                       // filter technical workspaces
+                                       if (workspaceName.startsWith(name)) {
+                                               Node workspaceNode = repoNode.hasNode(workspaceName) ? repoNode
+                                                               .getNode(workspaceName) : repoNode
+                                                               .addNode(workspaceName);
+                                               distributionElems.add(new DistributionElem(repoElem,
+                                                               workspaceNode));
+                                               // FIXME remove deleted workspaces
+                                       }
+                               }
+                               return distributionElems.toArray();
+                       } catch (RepositoryException e) {
+                               throw new SlcException("Cannot list workspaces for prefix "
+                                               + name, e);
+                       } finally {
+                               JcrUtils.logoutQuietly(session);
+                       }
+               }
+
+               public String getLabel() {
+                       return name;
+               }
+
+               public void dispose() {
+               }
+
+               public RepoElem getRepoElem() {
+                       return repoElem;
+               }
+
        }
 
        /** Abstracts a distribution, that is a workspace */
@@ -513,6 +710,10 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                public Credentials getCredentials() {
                        return repoElem.getCredentials();
                }
+
+               public boolean isReadOnly() {
+                       return repoElem.isReadOnly();
+               }
        }
 
        /** Listens to drag */
@@ -678,10 +879,11 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames
                        if (obj instanceof DistributionElem) {
                                DistributionElem distributionElem = (DistributionElem) obj;
                                DistributionEditorInput dei = new DistributionEditorInput(
-                                               distributionElem.getName(), distributionElem
-                                                               .getRepoElem().getRepository(),
-                                               distributionElem.getWorkspaceName(),
-                                               distributionElem.getCredentials());
+                                               distributionElem.getName(),
+                                               getRepositoryDescription(distributionElem.getRepoElem()),
+                                               distributionElem.getRepoElem().getRepository(),
+                                               distributionElem.getWorkspaceName(), distributionElem
+                                                               .getCredentials());
                                try {
                                        DistPlugin.getDefault().getWorkbench()
                                                        .getActiveWorkbenchWindow().getActivePage()