You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ja...@apache.org on 2013/10/28 18:03:54 UTC

svn commit: r1536411 [3/3] - in /ace/trunk: org.apache.ace.client.repository/src/org/apache/ace/client/repository/impl/ org.apache.ace.client.repository/src/org/apache/ace/client/repository/repository/ org.apache.ace.webui.vaadin/src/org/apache/ace/web...

Modified: ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/AssociationHelper.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/AssociationHelper.java?rev=1536411&r1=1536410&r2=1536411&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/AssociationHelper.java (original)
+++ ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/AssociationHelper.java Mon Oct 28 17:03:53 2013
@@ -39,6 +39,10 @@ public class AssociationHelper {
     private Set<?> m_activeSelection;
     private SelectionListener m_activeSelectionListener;
 
+    public void addAssociatedItem(RepositoryObject item) {
+        m_associatedItems.add(item);
+    }
+    
     public void removeAssociatedItem(RepositoryObject item) {
         m_associatedItems.remove(item);
     }

Modified: ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/BaseObjectPanel.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/BaseObjectPanel.java?rev=1536411&r1=1536410&r2=1536411&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/BaseObjectPanel.java (original)
+++ ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/BaseObjectPanel.java Mon Oct 28 17:03:53 2013
@@ -31,7 +31,7 @@ import org.apache.ace.client.repository.
 import org.apache.ace.webui.NamedObject;
 import org.apache.ace.webui.UIExtensionFactory;
 import org.apache.ace.webui.domain.NamedObjectFactory;
-import org.apache.ace.webui.vaadin.AssociationRemover;
+import org.apache.ace.webui.vaadin.AssociationManager;
 import org.apache.ace.webui.vaadin.EditWindow;
 import org.apache.felix.dm.Component;
 import org.apache.felix.dm.DependencyManager;
@@ -41,6 +41,12 @@ import org.osgi.service.event.EventHandl
 import com.vaadin.data.Item;
 import com.vaadin.event.ItemClickEvent;
 import com.vaadin.event.ItemClickEvent.ItemClickListener;
+import com.vaadin.event.Transferable;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.TargetDetails;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.Or;
 import com.vaadin.terminal.Resource;
 import com.vaadin.terminal.ThemeResource;
 import com.vaadin.ui.Button;
@@ -53,21 +59,76 @@ import com.vaadin.ui.themes.Reindeer;
 /**
  * Provides a custom table for displaying artifacts, features and so on.
  */
-abstract class BaseObjectPanel<REPO_OBJ extends RepositoryObject, REPO extends ObjectRepository<REPO_OBJ>> extends TreeTable implements EventHandler {
+abstract class BaseObjectPanel<REPO_OBJ extends RepositoryObject, REPO extends ObjectRepository<REPO_OBJ>, LEFT_ASSOC_REPO_OBJ extends RepositoryObject, RIGHT_ASSOC_REPO_OBJ extends RepositoryObject> extends TreeTable implements EventHandler {
+    /**
+     * Drop handler for associations.
+     */
+    private class AssociationDropHandler implements DropHandler {
+
+        public void drop(DragAndDropEvent event) {
+            Transferable transferable = event.getTransferable();
+
+            TargetDetails targetDetails = event.getTargetDetails();
+            if (!(transferable instanceof Table.TableTransferable) || !(targetDetails instanceof Table.AbstractSelectTargetDetails)) {
+                return;
+            }
+
+            Table.TableTransferable tt = (Table.TableTransferable) transferable;
+            Table.AbstractSelectTargetDetails ttd = (Table.AbstractSelectTargetDetails) targetDetails;
+
+            // get the active selection, but only if we drag from the same table
+            Set<?> selection = m_associations.isActiveTable(tt.getSourceComponent()) ? m_associations.getActiveSelection() : null;
+
+            Object fromItemId = tt.getItemId();
+            Object toItemId = ttd.getItemIdOver();
+
+            if (tt.getSourceComponent().equals(m_leftTable)) {
+                REPO_OBJ rightObject = getFromId((String) toItemId);
+
+                if (selection != null) {
+                    for (Object item : selection) {
+                        createLeftSideAssociation(m_leftTable.getFromId((String) item), rightObject);
+                    }
+                }
+                else {
+                    createLeftSideAssociation(m_leftTable.getFromId((String) fromItemId), rightObject);
+                }
+            }
+            else if (tt.getSourceComponent().equals(m_rightTable)) {
+                REPO_OBJ leftObject = getFromId((String) toItemId);
+
+                if (selection != null) {
+                    for (Object item : selection) {
+                        createRightSideAssociation(leftObject, m_rightTable.getFromId((String) item));
+                    }
+                }
+                else {
+                    createRightSideAssociation(leftObject, m_rightTable.getFromId((String) fromItemId));
+                }
+            }
+        }
+
+        public AcceptCriterion getAcceptCriterion() {
+            return new Or(VerticalLocationIs.MIDDLE);
+        }
+    }
 
     /**
      * Provides a generic remove item button.
      */
-    private class RemoveItemButton extends Button {
-        public RemoveItemButton(final REPO repository, final REPO_OBJ object) {
+    protected class RemoveItemButton extends Button {
+        public RemoveItemButton(final REPO_OBJ object) {
             super("x");
             setStyleName(Reindeer.BUTTON_SMALL);
             setDescription("Delete " + getDisplayName(object));
 
             addListener(new Button.ClickListener() {
                 public void buttonClick(ClickEvent event) {
+                    // Give some clue that this click is being processed...
+                    event.getButton().setEnabled(false);
+
                     try {
-                        repository.remove(object);
+                        getRepository().remove(object);
                     }
                     catch (Exception e) {
                         // ACE-246: notify user when the removal failed!
@@ -82,8 +143,8 @@ abstract class BaseObjectPanel<REPO_OBJ 
     /**
      * Provides a generic remove-link (or association) button.
      */
-    private class RemoveLinkButton extends Button {
-        public RemoveLinkButton(final REPO_OBJ object, final Table toLeft, final Table toRight) {
+    protected class RemoveLinkButton extends Button {
+        public RemoveLinkButton(final REPO_OBJ object) {
             super("-");
             setStyleName(Reindeer.BUTTON_SMALL);
             setData(object.getDefinition());
@@ -93,18 +154,19 @@ abstract class BaseObjectPanel<REPO_OBJ 
 
             addListener(new Button.ClickListener() {
                 public void buttonClick(ClickEvent event) {
+                    // Give some clue that this click is being processed...
+                    event.getButton().setEnabled(false);
+
                     Set<?> selection = m_associations.getActiveSelection();
                     if (selection != null) {
-                        if (m_associations.isActiveTable(toLeft)) {
-                            for (Object item : selection) {
-                                RepositoryObject selected = m_associations.lookupInActiveSelection(item);
-                                removeLeftSideAssociation(object, selected);
+                        if (m_associations.isActiveTable(m_leftTable)) {
+                            for (Object itemId : selection) {
+                                removeLeftSideAssociation(m_leftTable.getFromId((String) itemId), object);
                             }
                         }
-                        else if (m_associations.isActiveTable(toRight)) {
-                            for (Object item : selection) {
-                                RepositoryObject selected = m_associations.lookupInActiveSelection(item);
-                                removeRightSideAssocation(object, selected);
+                        else if (m_associations.isActiveTable(m_rightTable)) {
+                            for (Object itemId : selection) {
+                                removeRightSideAssocation(object, m_rightTable.getFromId((String) itemId));
                             }
                         }
                     }
@@ -180,14 +242,14 @@ abstract class BaseObjectPanel<REPO_OBJ 
     /** Empirically determined (most common width appears to be 36px). */
     protected static final int FIXED_COLUMN_WIDTH = 36;
 
-    private final AssociationHelper m_associations;
-    protected final AssociationRemover m_associationRemover;
+    protected final AssociationHelper m_associations;
+    protected final AssociationManager m_associationManager;
 
     private final List<UIExtensionFactoryHolder> m_extensionFactories;
     private final String m_extensionPoint;
 
-    private Table m_leftTable;
-    private Table m_rightTable;
+    protected BaseObjectPanel<LEFT_ASSOC_REPO_OBJ, ?, ?, ?> m_leftTable;
+    protected BaseObjectPanel<RIGHT_ASSOC_REPO_OBJ, ?, ?, ?> m_rightTable;
 
     /**
      * Creates a new {@link BaseObjectPanel} instance.
@@ -204,12 +266,12 @@ abstract class BaseObjectPanel<REPO_OBJ 
      *            <code>true</code> if double clicking an row in this table should show an editor, <code>false</code> to
      *            disallow editing.
      */
-    public BaseObjectPanel(final AssociationHelper associations, final AssociationRemover associationRemover,
+    public BaseObjectPanel(final AssociationHelper associations, final AssociationManager associationRemover,
         final String name, final String extensionPoint, final boolean hasEdit) {
         super(name + "s");
 
         m_associations = associations;
-        m_associationRemover = associationRemover;
+        m_associationManager = associationRemover;
         m_extensionFactories = new ArrayList<UIExtensionFactoryHolder>();
         m_extensionPoint = extensionPoint;
 
@@ -266,12 +328,7 @@ abstract class BaseObjectPanel<REPO_OBJ 
 
         synchronized (getApplication()) {
             if (isSupportedEntity(entity)) {
-                try {
-                    handleEvent(topic, entity, event);
-                }
-                finally {
-                    refreshRenderedCells();
-                }
+                handleEvent(topic, entity, event);
             }
             else if (RepositoryAdmin.TOPIC_REFRESH.equals(topic) || RepositoryAdmin.TOPIC_LOGIN.equals(topic)) {
                 populate();
@@ -322,36 +379,67 @@ abstract class BaseObjectPanel<REPO_OBJ 
     }
 
     /**
-     * Sets the left-side table, that defines the left-hand side of the assocations of the entities.
+     * Sets the tables that are associated this this panel.
      * 
      * @param leftTable
-     *            the table to set, can be <code>null</code>.
+     *            the left-side table to associate with, can be <code>null</code>;
+     * @param rightTable
+     *            the right-side table to associate with, can be <code>null</code>.
      */
-    public final void setLeftTable(Table leftTable) {
+    public final void setAssociatedTables(BaseObjectPanel<LEFT_ASSOC_REPO_OBJ, ?, ?, ?> leftTable, BaseObjectPanel<RIGHT_ASSOC_REPO_OBJ, ?, ?, ?> rightTable) {
         m_leftTable = leftTable;
+        m_rightTable = rightTable;
+
+        setDropHandler(new AssociationDropHandler());
     }
 
     /**
-     * Sets the right-side table, that defines the right-hand side of the assocations of the entities.
+     * Creates the left-hand side associations for a given repository object.
      * 
-     * @param rightTable
-     *            the table to set, can be <code>null</code>.
+     * @param leftObject
+     *            the (left-hand side) repository object to create the associations for.
+     * @param rightObject
+     *            the repository object to create the left-hand side associations;
      */
-    public final void setRightTable(Table rightTable) {
-        m_rightTable = rightTable;
+    final void createLeftSideAssociation(LEFT_ASSOC_REPO_OBJ leftObject, REPO_OBJ rightObject) {
+        if (doCreateLeftSideAssociation(leftObject, rightObject)) {
+            m_associations.addAssociatedItem(rightObject);
+            refreshRowCache();
+            if (m_leftTable != null) {
+                m_leftTable.refreshRowCache();
+            }
+        }
+    }
+
+    /**
+     * Creates the right-hand side associations for a given repository object.
+     * 
+     * @param leftObject
+     *            the repository object to create the right-hand side associations;
+     * @param rightObject
+     *            the (right-hand side) repository object to create the associations for.
+     */
+    final void createRightSideAssociation(REPO_OBJ leftObject, RIGHT_ASSOC_REPO_OBJ rightObject) {
+        if (doCreateRightSideAssociation(leftObject, rightObject)) {
+            m_associations.addAssociatedItem(leftObject);
+            refreshRowCache();
+            if (m_rightTable != null) {
+                m_rightTable.refreshRowCache();
+            }
+        }
     }
 
     /**
      * Removes the left-hand side associations for a given repository object.
      * 
-     * @param object
-     *            the repository object to remove the left-hand side associations;
-     * @param other
+     * @param leftObject
      *            the (left-hand side) repository object to remove the associations for.
+     * @param rightObject
+     *            the repository object to remove the left-hand side associations;
      */
-    final void removeLeftSideAssociation(REPO_OBJ object, RepositoryObject other) {
-        if (doRemoveLeftSideAssociation(object, other)) {
-            m_associations.removeAssociatedItem(object);
+    final void removeLeftSideAssociation(LEFT_ASSOC_REPO_OBJ leftObject, REPO_OBJ rightObject) {
+        if (doRemoveLeftSideAssociation(leftObject, rightObject)) {
+            m_associations.removeAssociatedItem(rightObject);
             refreshRowCache();
             if (m_leftTable != null) {
                 m_leftTable.refreshRowCache();
@@ -362,14 +450,14 @@ abstract class BaseObjectPanel<REPO_OBJ 
     /**
      * Removes the right-hand side associations for a given repository object.
      * 
-     * @param object
+     * @param leftObject
      *            the repository object to remove the right-hand side associations;
-     * @param other
+     * @param rightObject
      *            the (right-hand side) repository object to remove the associations for.
      */
-    final void removeRightSideAssocation(REPO_OBJ object, RepositoryObject other) {
-        if (doRemoveRightSideAssociation(object, other)) {
-            m_associations.removeAssociatedItem(object);
+    final void removeRightSideAssocation(REPO_OBJ leftObject, RIGHT_ASSOC_REPO_OBJ rightObject) {
+        if (doRemoveRightSideAssociation(leftObject, rightObject)) {
+            m_associations.removeAssociatedItem(leftObject);
             refreshRowCache();
             if (m_rightTable != null) {
                 m_rightTable.refreshRowCache();
@@ -383,26 +471,29 @@ abstract class BaseObjectPanel<REPO_OBJ 
      * @param object
      *            the repository object to add, cannot be <code>null</code>.
      */
-    protected void add(REPO_OBJ object) {
-        Item item = addItem(object.getDefinition());
-        if (item != null) {
-            setChildrenAllowed(object.getDefinition(), false);
+    protected final void add(REPO_OBJ object) {
+        String itemId = object.getDefinition();
+        String parentId = getParentId(object);
+
+        if ((parentId != null) && !containsId(parentId)) {
+            Item parentItem = addItem(parentId);
+            if (parentItem != null) {
+                populateParentItem(object, parentId, parentItem);
+            }
+        }
 
+        Item item = addItem(itemId);
+        if (item != null) {
             populateItem(object, item);
-            setItemIcon(object);
         }
-    }
 
-    protected void updateItemIcon(Object itemId) {
-        REPO_OBJ obj = getFromId((String) itemId);
-        setItemIcon(obj);
-    }
-
-    protected void setItemIcon(REPO_OBJ object) {
-        if (object != null) {
-            Resource icon = getWorkingStateIcon(object);
-            setItemIcon(object.getDefinition(), icon);
+        if (parentId != null) {
+            setParent(itemId, parentId);
+            setCollapsed(parentId, false);
+            setItemIcon(object);
         }
+
+        setChildrenAllowed(itemId, false);
     }
 
     protected abstract EditWindow createEditor(NamedObject object, List<UIExtensionFactory> extensions);
@@ -437,28 +528,6 @@ abstract class BaseObjectPanel<REPO_OBJ 
     }
 
     /**
-     * Factory method to create a remove-item button.
-     * 
-     * @param object
-     *            the repository object to create the remove-item button for, cannot be <code>null</code>.
-     * @return a button, can be <code>null</code> if removal of this repository object is not supported.
-     */
-    protected Button createRemoveItemButton(REPO_OBJ object) {
-        return new RemoveItemButton(getRepository(), object);
-    }
-
-    /**
-     * Factory method to create a remove-link button.
-     * 
-     * @param object
-     *            the repository object to create the remove-link button for, cannot be <code>null</code>.
-     * @return a button, can be <code>null</code> if remove-link is not supported.
-     */
-    protected Button createUnlinkButton(REPO_OBJ object) {
-        return new RemoveLinkButton(object, m_leftTable, m_rightTable);
-    }
-
-    /**
      * Defines the table columns for this panel.
      */
     protected void defineTableColumns() {
@@ -478,28 +547,46 @@ abstract class BaseObjectPanel<REPO_OBJ 
     }
 
     /**
+     * @param leftObject
+     * @param rightObject
+     * @return
+     */
+    protected boolean doCreateLeftSideAssociation(LEFT_ASSOC_REPO_OBJ leftObject, REPO_OBJ rightObject) {
+        return m_leftTable != null;
+    }
+
+    /**
+     * @param leftObject
+     * @param rightObject
+     * @return
+     */
+    protected boolean doCreateRightSideAssociation(REPO_OBJ leftObject, RIGHT_ASSOC_REPO_OBJ rightObject) {
+        return m_rightTable != null;
+    }
+
+    /**
      * Does the actual removal of the left-hand side associations for a given repository object.
      * 
-     * @param object
-     *            the repository object to remove the left-hand side associations;
-     * @param other
+     * @param leftObject
      *            the (left-hand side) repository object to remove the associations for.
+     * @param rightObject
+     *            the repository object to remove the left-hand side associations;
      * @return <code>true</code> if the associations were removed, <code>false</code> if not.
      */
-    protected boolean doRemoveLeftSideAssociation(REPO_OBJ object, RepositoryObject other) {
+    protected boolean doRemoveLeftSideAssociation(LEFT_ASSOC_REPO_OBJ leftObject, REPO_OBJ rightObject) {
         return m_leftTable != null;
     }
 
     /**
      * Does the actual removal of the right-hand side associations for a given repository object.
      * 
-     * @param object
+     * @param leftObject
      *            the repository object to remove the right-hand side associations;
-     * @param other
+     * @param rightObject
      *            the (right-hand side) repository object to remove the associations for.
      * @return <code>true</code> if the associations were removed, <code>false</code> if not.
      */
-    protected boolean doRemoveRightSideAssociation(REPO_OBJ object, RepositoryObject other) {
+    protected boolean doRemoveRightSideAssociation(REPO_OBJ leftObject, RIGHT_ASSOC_REPO_OBJ rightObject) {
         return m_rightTable != null;
     }
 
@@ -525,6 +612,26 @@ abstract class BaseObjectPanel<REPO_OBJ 
     }
 
     /**
+     * @param object
+     * @return a display name for the parent of the given repository object, cannot be <code>null</code>.
+     */
+    protected String getParentDisplayName(REPO_OBJ object) {
+        return object.getDefinition();
+    }
+
+    /**
+     * Determines the parent Id of a given repository object.
+     * 
+     * @param object
+     *            the repository object to determine the parent for, cannot be <code>null</code>.
+     * @return the ID of the parent for the given repository object, or <code>null</code> in case no parent could be
+     *         determined.
+     */
+    protected String getParentId(REPO_OBJ object) {
+        return null;
+    }
+
+    /**
      * Returns the actual repository for objects.
      * 
      * @return the actual repository for obtaining the repository objects, cannot be <code>null</code>.
@@ -593,13 +700,45 @@ abstract class BaseObjectPanel<REPO_OBJ 
     protected abstract void populateItem(REPO_OBJ object, Item item);
 
     /**
+     * Populates the given table item with information about the parent for a given repository object.
+     * 
+     * @param object
+     *            the repository object to take the information from, cannot be <code>null</code>;
+     * @param parentId
+     *            the ID of the parent, cannot be <code>null</code>;
+     * @param item
+     *            the table item to populate, cannot be <code>null</code>.
+     */
+    protected void populateParentItem(REPO_OBJ object, String parentId, Item item) {
+        item.getItemProperty(OBJECT_NAME).setValue(getParentDisplayName(object));
+        item.getItemProperty(OBJECT_DESCRIPTION).setValue("");
+        // we *must* set a non-null icon for the parent as well to ensure that the tree-table open/collapse icon is
+        // rendered properly...
+        setItemIcon(parentId, createIconResource("resource_workingstate_unchanged"));
+    }
+
+    /**
      * Removes a given repository object from this table.
      * 
      * @param object
      *            the repository object to remove, cannot be <code>null</code>.
      */
-    protected void remove(REPO_OBJ object) {
-        removeItem(object.getDefinition());
+    protected final void remove(REPO_OBJ object) {
+        String itemID = object.getDefinition();
+        Object parentID = getParent(itemID);
+
+        if (removeItem(itemID)) {
+            if (!hasChildren(parentID)) {
+                removeItem(parentID);
+            }
+        }
+    }
+
+    protected final void setItemIcon(REPO_OBJ object) {
+        if (object != null) {
+            Resource icon = getWorkingStateIcon(object);
+            setItemIcon(object.getDefinition(), icon);
+        }
     }
 
     /**
@@ -608,7 +747,7 @@ abstract class BaseObjectPanel<REPO_OBJ 
      * @param object
      *            the repository object to update, cannot be <code>null</code>.
      */
-    protected void update(REPO_OBJ object) {
+    protected final void update(REPO_OBJ object) {
         if (object != null) {
             String definition = object.getDefinition();
             if (definition != null) {
@@ -620,6 +759,11 @@ abstract class BaseObjectPanel<REPO_OBJ 
         }
     }
 
+    protected final void updateItemIcon(Object itemId) {
+        REPO_OBJ obj = getFromId((String) itemId);
+        setItemIcon(obj);
+    }
+
     /**
      * Returns all repository objects.
      * 

Modified: ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/DistributionsPanel.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/DistributionsPanel.java?rev=1536411&r1=1536410&r2=1536411&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/DistributionsPanel.java (original)
+++ ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/DistributionsPanel.java Mon Oct 28 17:03:53 2013
@@ -26,17 +26,17 @@ import org.apache.ace.client.repository.
 import org.apache.ace.client.repository.object.DistributionObject;
 import org.apache.ace.client.repository.object.Feature2DistributionAssociation;
 import org.apache.ace.client.repository.object.FeatureObject;
-import org.apache.ace.client.repository.object.TargetObject;
 import org.apache.ace.client.repository.repository.DistributionRepository;
+import org.apache.ace.client.repository.stateful.StatefulTargetObject;
 import org.apache.ace.webui.UIExtensionFactory;
-import org.apache.ace.webui.vaadin.AssociationRemover;
+import org.apache.ace.webui.vaadin.AssociationManager;
 
 import com.vaadin.data.Item;
 
 /**
  * Provides an object panel for displaying distributions.
  */
-public abstract class DistributionsPanel extends BaseObjectPanel<DistributionObject, DistributionRepository> {
+public abstract class DistributionsPanel extends BaseObjectPanel<DistributionObject, DistributionRepository, FeatureObject, StatefulTargetObject> {
 
     /**
      * Creates a new {@link DistributionsPanel} instance.
@@ -46,25 +46,37 @@ public abstract class DistributionsPanel
      * @param associationRemover
      *            the helper for removing associations.
      */
-    public DistributionsPanel(AssociationHelper associations, AssociationRemover associationRemover) {
+    public DistributionsPanel(AssociationHelper associations, AssociationManager associationRemover) {
         super(associations, associationRemover, "Distribution", UIExtensionFactory.EXTENSION_POINT_VALUE_DISTRIBUTION,
             true /* hasEdit */);
     }
 
     @Override
-    protected boolean doRemoveLeftSideAssociation(DistributionObject object, RepositoryObject other) {
-        List<Feature2DistributionAssociation> associations = object.getAssociationsWith((FeatureObject) other);
+    protected boolean doCreateLeftSideAssociation(FeatureObject feature, DistributionObject distribution) {
+        m_associationManager.createFeature2DistributionAssociation(feature, distribution);
+        return true;
+    }
+
+    @Override
+    protected boolean doCreateRightSideAssociation(DistributionObject distribution, StatefulTargetObject target) {
+        m_associationManager.createDistribution2TargetAssociation(distribution, target);
+        return true;
+    }
+
+    @Override
+    protected boolean doRemoveLeftSideAssociation(FeatureObject feature, DistributionObject object) {
+        List<Feature2DistributionAssociation> associations = object.getAssociationsWith(feature);
         for (Feature2DistributionAssociation association : associations) {
-            m_associationRemover.removeAssociation(association);
+            m_associationManager.removeAssociation(association);
         }
         return true;
     }
 
     @Override
-    protected boolean doRemoveRightSideAssociation(DistributionObject object, RepositoryObject other) {
-        List<Distribution2TargetAssociation> associations = object.getAssociationsWith((TargetObject) other);
+    protected boolean doRemoveRightSideAssociation(DistributionObject object, StatefulTargetObject target) {
+        List<Distribution2TargetAssociation> associations = object.getAssociationsWith(target.getTargetObject());
         for (Distribution2TargetAssociation association : associations) {
-            m_associationRemover.removeAssociation(association);
+            m_associationManager.removeAssociation(association);
         }
         return true;
     }
@@ -97,7 +109,7 @@ public abstract class DistributionsPanel
     protected void populateItem(DistributionObject distribution, Item item) {
         item.getItemProperty(OBJECT_NAME).setValue(distribution.getName());
         item.getItemProperty(OBJECT_DESCRIPTION).setValue(distribution.getDescription());
-        item.getItemProperty(ACTION_UNLINK).setValue(createUnlinkButton(distribution));
-        item.getItemProperty(ACTION_DELETE).setValue(createRemoveItemButton(distribution));
+        item.getItemProperty(ACTION_UNLINK).setValue(new RemoveLinkButton(distribution));
+        item.getItemProperty(ACTION_DELETE).setValue(new RemoveItemButton(distribution));
     }
 }

Modified: ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/FeaturesPanel.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/FeaturesPanel.java?rev=1536411&r1=1536410&r2=1536411&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/FeaturesPanel.java (original)
+++ ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/FeaturesPanel.java Mon Oct 28 17:03:53 2013
@@ -29,14 +29,14 @@ import org.apache.ace.client.repository.
 import org.apache.ace.client.repository.object.FeatureObject;
 import org.apache.ace.client.repository.repository.FeatureRepository;
 import org.apache.ace.webui.UIExtensionFactory;
-import org.apache.ace.webui.vaadin.AssociationRemover;
+import org.apache.ace.webui.vaadin.AssociationManager;
 
 import com.vaadin.data.Item;
 
 /**
  * Provides an object panel for displaying features.
  */
-public abstract class FeaturesPanel extends BaseObjectPanel<FeatureObject, FeatureRepository> {
+public abstract class FeaturesPanel extends BaseObjectPanel<FeatureObject, FeatureRepository, ArtifactObject, DistributionObject> {
 
     /**
      * Creates a new {@link FeaturesPanel} instance.
@@ -46,28 +46,40 @@ public abstract class FeaturesPanel exte
      * @param associationRemover
      *            the helper for removing associations.
      */
-    public FeaturesPanel(AssociationHelper associations, AssociationRemover associationRemover) {
+    public FeaturesPanel(AssociationHelper associations, AssociationManager associationRemover) {
         super(associations, associationRemover, "Feature", UIExtensionFactory.EXTENSION_POINT_VALUE_FEATURE, true);
     }
 
     @Override
-    protected boolean doRemoveLeftSideAssociation(FeatureObject object, RepositoryObject other) {
-        List<Artifact2FeatureAssociation> associations = object.getAssociationsWith((ArtifactObject) other);
+    protected boolean doCreateLeftSideAssociation(ArtifactObject artifact, FeatureObject feature) {
+        m_associationManager.createArtifact2FeatureAssociation(artifact, feature);
+        return true;
+    }
+
+    @Override
+    protected boolean doCreateRightSideAssociation(FeatureObject feature, DistributionObject distribution) {
+        m_associationManager.createFeature2DistributionAssociation(feature, distribution);
+        return true;
+    }
+
+    @Override
+    protected boolean doRemoveLeftSideAssociation(ArtifactObject artifact, FeatureObject feature) {
+        List<Artifact2FeatureAssociation> associations = feature.getAssociationsWith(artifact);
         for (Artifact2FeatureAssociation association : associations) {
-            m_associationRemover.removeAssociation(association);
+            m_associationManager.removeAssociation(association);
         }
         return true;
     }
 
     @Override
-    protected boolean doRemoveRightSideAssociation(FeatureObject object, RepositoryObject other) {
-        List<Feature2DistributionAssociation> associations = object.getAssociationsWith((DistributionObject) other);
+    protected boolean doRemoveRightSideAssociation(FeatureObject feature, DistributionObject distribution) {
+        List<Feature2DistributionAssociation> associations = feature.getAssociationsWith(distribution);
         for (Feature2DistributionAssociation association : associations) {
-            m_associationRemover.removeAssociation(association);
+            m_associationManager.removeAssociation(association);
         }
         return true;
     }
-    
+
     @Override
     protected String getDisplayName(FeatureObject object) {
         return object.getName();
@@ -96,7 +108,7 @@ public abstract class FeaturesPanel exte
     protected void populateItem(FeatureObject feature, Item item) {
         item.getItemProperty(OBJECT_NAME).setValue(feature.getName());
         item.getItemProperty(OBJECT_DESCRIPTION).setValue(feature.getDescription());
-        item.getItemProperty(ACTION_UNLINK).setValue(createUnlinkButton(feature));
-        item.getItemProperty(ACTION_DELETE).setValue(createRemoveItemButton(feature));
+        item.getItemProperty(ACTION_UNLINK).setValue(new RemoveLinkButton(feature));
+        item.getItemProperty(ACTION_DELETE).setValue(new RemoveItemButton(feature));
     }
 }

Modified: ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/MainActionToolbar.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/MainActionToolbar.java?rev=1536411&r1=1536410&r2=1536411&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/MainActionToolbar.java (original)
+++ ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/MainActionToolbar.java Mon Oct 28 17:03:53 2013
@@ -87,7 +87,8 @@ public abstract class MainActionToolbar 
         }
 
         /**
-         * @param e the exception to handle.
+         * @param e
+         *            the exception to handle.
          */
         private void handleIOException(IOException e) {
             getWindow().showNotification("Warning",
@@ -98,7 +99,8 @@ public abstract class MainActionToolbar 
         /**
          * Does the actual logout of the user.
          * 
-         * @throws IOException in case of I/O problems during the logout.
+         * @throws IOException
+         *             in case of I/O problems during the logout.
          */
         private void logout() throws IOException {
             getRepositoryAdmin().logout(true /* force */);
@@ -147,7 +149,8 @@ public abstract class MainActionToolbar 
         }
 
         /**
-         * @param e the exception to handle.
+         * @param e
+         *            the exception to handle.
          */
         private void handleIOException(IOException e) {
             getWindow().showNotification("Retrieve failed",
@@ -158,7 +161,8 @@ public abstract class MainActionToolbar 
         /**
          * Does the actual retrieval of the latest version.
          * 
-         * @throws IOException in case of I/O problems during the retrieve.
+         * @throws IOException
+         *             in case of I/O problems during the retrieve.
          */
         private void retrieveData() throws IOException {
             getRepositoryAdmin().checkout();
@@ -208,7 +212,8 @@ public abstract class MainActionToolbar 
         }
 
         /**
-         * @param e the exception to handle.
+         * @param e
+         *            the exception to handle.
          */
         private void handleIOException(IOException e) {
             getWindow().showNotification("Revert failed",
@@ -218,7 +223,8 @@ public abstract class MainActionToolbar 
         /**
          * Does the actual revert of changes.
          * 
-         * @throws IOException in case of problems during I/O exception.
+         * @throws IOException
+         *             in case of problems during I/O exception.
          */
         private void revertChanges() throws IOException {
             getRepositoryAdmin().revert();
@@ -263,7 +269,8 @@ public abstract class MainActionToolbar 
         /**
          * Does the actual commit of changes.
          * 
-         * @throws IOException in case of I/O problems during the commit.
+         * @throws IOException
+         *             in case of I/O problems during the commit.
          */
         private void commitChanges() throws IOException {
             getRepositoryAdmin().commit();
@@ -278,84 +285,67 @@ public abstract class MainActionToolbar 
     private Button m_revertButton;
     private Button m_logoutButton;
 
-    private final DependencyManager m_manager;
     private final ConcurrentHashMap<ServiceReference, UIExtensionFactory> m_extensions = new ConcurrentHashMap<ServiceReference, UIExtensionFactory>();
 
     private final User m_user;
 
-	private HorizontalLayout m_extraComponentBar;
+    private HorizontalLayout m_extraComponentBar;
 
     /**
      * Creates a new {@link MainActionToolbar} instance.
-     * @param user 
-     * @param manager 
      * 
-     * @param showLogoutButton <code>true</code> if a logout button should be shown, <code>false</code> if it should not.
+     * @param user
+     * @param manager
+     * 
+     * @param showLogoutButton
+     *            <code>true</code> if a logout button should be shown, <code>false</code> if it should not.
      */
     public MainActionToolbar(User user, DependencyManager manager, boolean showLogoutButton) {
         super(5, 1);
-        m_user = user;
-        m_manager = manager;
 
+        m_user = user;
         m_showLogoutButton = showLogoutButton;
 
         setWidth("100%");
         setSpacing(true);
-        
+
         initComponent();
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public void handleEvent(org.osgi.service.event.Event event) {
+        boolean modified = false;
+        try {
+            modified = getRepositoryAdmin().isModified();
+        }
+        catch (IOException e) {
+            getWindow().showNotification("Communication failed!",
+                "Failed to communicate with the server.<br />Reason: " + e.getMessage(),
+                Notification.TYPE_ERROR_MESSAGE);
+        }
+
+        m_storeButton.setEnabled(modified);
+        m_revertButton.setEnabled(modified);
+    }
+
     public void init(org.apache.felix.dm.Component component) {
-    	DependencyManager dm = component.getDependencyManager();
-    	component.add(dm.createServiceDependency()
+        DependencyManager dm = component.getDependencyManager();
+        component.add(dm.createServiceDependency()
             .setService(UIExtensionFactory.class, "(" + UIExtensionFactory.EXTENSION_POINT_KEY + "=" + UIExtensionFactory.EXTENSION_POINT_VALUE_MENU + ")")
             .setCallbacks("add", "remove")
             .setRequired(false)
             .setInstanceBound(true)
-        );
-    }
-    
-    public void add(ServiceReference ref, UIExtensionFactory factory) {
-        m_extensions.put(ref, factory);
-        setExtraComponents();
+            );
     }
 
-	private void setExtraComponents() {
-		m_extraComponentBar.removeAllComponents();
-		for (Component c : getExtraComponents()) {
-			m_extraComponentBar.addComponent(c);
-		}
-	}
-    
-    public void remove(ServiceReference ref,  UIExtensionFactory factory) {
-        m_extensions.remove(ref);
+    protected final void add(ServiceReference ref, UIExtensionFactory factory) {
+        m_extensions.put(ref, factory);
         setExtraComponents();
     }
 
     /**
-     * {@inheritDoc}
-     */
-    public void handleEvent(org.osgi.service.event.Event event) {
-        String topic = event.getTopic();
-        if (RepositoryAdmin.TOPIC_STATUSCHANGED.equals(topic) || RepositoryAdmin.TOPIC_REFRESH.equals(topic)
-            || RepositoryAdmin.TOPIC_LOGIN.equals(topic)) {
-
-            boolean modified = false;
-            try {
-                modified = getRepositoryAdmin().isModified();
-            }
-            catch (IOException e) {
-                getWindow().showNotification("Communication failed!",
-                    "Failed to communicate with the server.<br />Reason: " + e.getMessage(),
-                    Notification.TYPE_ERROR_MESSAGE);
-            }
-
-            m_storeButton.setEnabled(modified);
-            m_revertButton.setEnabled(modified);
-        }
-    }
-
-    /**
      * Called after a commit/store has taken place, allows additional UI-updates to be performed.
      * 
      * @throws IOException
@@ -383,11 +373,26 @@ public abstract class MainActionToolbar 
      */
     protected abstract void doAfterRevert() throws IOException;
 
+    protected final List<Component> getExtraComponents() {
+        List<Component> result = new ArrayList<Component>();
+        for (UIExtensionFactory f : m_extensions.values()) {
+            Map<String, Object> context = new HashMap<String, Object>();
+            context.put("user", m_user);
+            result.add(f.create(context));
+        }
+        return result;
+    }
+
     /**
      * @return a repository admin instance, never <code>null</code>.
      */
     protected abstract RepositoryAdmin getRepositoryAdmin();
 
+    protected final void remove(ServiceReference ref, UIExtensionFactory factory) {
+        m_extensions.remove(ref);
+        setExtraComponents();
+    }
+
     /**
      * Initializes this component.
      */
@@ -420,14 +425,11 @@ public abstract class MainActionToolbar 
         // button to appear at the right side of the screen....
         setColumnExpandRatio(3, 5);
     }
-    
-    protected List<Component> getExtraComponents() {
-        List<Component> result = new ArrayList<Component>();
-        for (UIExtensionFactory f : m_extensions.values()) {
-            Map<String, Object> context = new HashMap<String, Object>();
-            context.put("user", m_user);
-            result.add(f.create(context));
+
+    private void setExtraComponents() {
+        m_extraComponentBar.removeAllComponents();
+        for (Component c : getExtraComponents()) {
+            m_extraComponentBar.addComponent(c);
         }
-        return result;
     }
 }

Added: ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/StatusLine.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/StatusLine.java?rev=1536411&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/StatusLine.java (added)
+++ ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/StatusLine.java Mon Oct 28 17:03:53 2013
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.ace.webui.vaadin.component;
+
+import org.apache.ace.client.repository.RepositoryObject;
+import org.apache.ace.client.repository.object.Artifact2FeatureAssociation;
+import org.apache.ace.client.repository.object.ArtifactObject;
+import org.apache.ace.client.repository.object.Distribution2TargetAssociation;
+import org.apache.ace.client.repository.object.DistributionObject;
+import org.apache.ace.client.repository.object.Feature2DistributionAssociation;
+import org.apache.ace.client.repository.object.FeatureObject;
+import org.apache.ace.client.repository.object.TargetObject;
+import org.apache.ace.webui.NamedObject;
+import org.apache.ace.webui.domain.NamedObjectFactory;
+import org.osgi.service.event.EventHandler;
+
+import com.vaadin.ui.Label;
+
+/**
+ * Denotes a status line in which a short summary of the latest actions in the UI are displayed.
+ */
+@SuppressWarnings("unchecked")
+public class StatusLine extends Label implements EventHandler {
+
+    /**
+     * Creates a new {@link StatusLine} instance.
+     */
+    public StatusLine() {
+        setImmediate(true);
+    }
+
+    @Override
+    public void handleEvent(org.osgi.service.event.Event event) {
+        String topic = event.getTopic();
+        RepositoryObject entity = (RepositoryObject) event.getProperty(RepositoryObject.EVENT_ENTITY);
+
+        String type = getType(topic);
+        String action = getAction(topic);
+        String name = getName(entity);
+
+        if (type != null) {
+            if (name != null) {
+                setStatus("%s '%s' %s...", type, name, action);
+            }
+            else if (action != null) {
+                setStatus("%s %s...", type, action);
+            }
+        }
+    }
+
+    /**
+     * Sets the status to the given message.
+     * 
+     * @param msg
+     *            the message;
+     * @param args
+     *            the (optional) arguments.
+     */
+    public void setStatus(String msg, Object... args) {
+        setValue(String.format(msg, args));
+    }
+
+    /**
+     * @param topic
+     * @return
+     */
+    private String getAction(String topic) {
+        if (topic.endsWith("/" + RepositoryObject.TOPIC_REMOVED_SUFFIX)) {
+            return "removed";
+        }
+        else if (topic.endsWith("/" + RepositoryObject.TOPIC_ADDED_SUFFIX)) {
+            return "added";
+        }
+        else if (topic.endsWith("/" + RepositoryObject.TOPIC_CHANGED_SUFFIX)) {
+            return "changed";
+        }
+        return null;
+    }
+
+    private String getName(RepositoryObject entity) {
+        NamedObject obj = NamedObjectFactory.getNamedObject(entity);
+        if (obj == null) {
+            return null;
+        }
+        String name = obj.getName();
+        return name == null || "".equals(name.trim()) ? null : name;
+    }
+
+    private String getType(String topic) {
+        if (topic.contains(ArtifactObject.TOPIC_ENTITY_ROOT)) {
+            return "Artifact";
+        }
+        else if (topic.contains(FeatureObject.TOPIC_ENTITY_ROOT)) {
+            return "Feature";
+        }
+        else if (topic.contains(DistributionObject.TOPIC_ENTITY_ROOT)) {
+            return "Distribution";
+        }
+        else if (topic.contains(TargetObject.TOPIC_ENTITY_ROOT)) {
+            return "Target";
+        }
+        else if (topic.contains(Artifact2FeatureAssociation.TOPIC_ENTITY_ROOT)
+            || topic.contains(Feature2DistributionAssociation.TOPIC_ENTITY_ROOT)
+            || topic.contains(Distribution2TargetAssociation.TOPIC_ENTITY_ROOT)) {
+            return "Association";
+        }
+        return null;
+    }
+}

Propchange: ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/StatusLine.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/TargetsPanel.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/TargetsPanel.java?rev=1536411&r1=1536410&r2=1536411&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/TargetsPanel.java (original)
+++ ace/trunk/org.apache.ace.webui.vaadin/src/org/apache/ace/webui/vaadin/component/TargetsPanel.java Mon Oct 28 17:03:53 2013
@@ -28,7 +28,7 @@ import org.apache.ace.client.repository.
 import org.apache.ace.client.repository.stateful.StatefulTargetObject;
 import org.apache.ace.client.repository.stateful.StatefulTargetRepository;
 import org.apache.ace.webui.UIExtensionFactory;
-import org.apache.ace.webui.vaadin.AssociationRemover;
+import org.apache.ace.webui.vaadin.AssociationManager;
 
 import com.vaadin.data.Item;
 import com.vaadin.terminal.Resource;
@@ -38,7 +38,7 @@ import com.vaadin.ui.Embedded;
 /**
  * Provides an object panel for displaying (stateful) targets.
  */
-public abstract class TargetsPanel extends BaseObjectPanel<StatefulTargetObject, StatefulTargetRepository> {
+public abstract class TargetsPanel extends BaseObjectPanel<StatefulTargetObject, StatefulTargetRepository, DistributionObject, RepositoryObject> {
 
     private static final String REGISTRATION_STATE_ICON = "regStateIcon";
     private static final String PROVISIONING_STATE_ICON = "provStateIcon";
@@ -52,17 +52,10 @@ public abstract class TargetsPanel exten
      * @param associationRemover
      *            the helper for removing associations.
      */
-    public TargetsPanel(AssociationHelper associations, AssociationRemover associationRemover) {
+    public TargetsPanel(AssociationHelper associations, AssociationManager associationRemover) {
         super(associations, associationRemover, "Target", UIExtensionFactory.EXTENSION_POINT_VALUE_TARGET, true /* hasEdit */);
     }
 
-    @Override
-    protected Button createRemoveItemButton(StatefulTargetObject object) {
-        Button b = super.createRemoveItemButton(object);
-        b.setEnabled(object.isRegistered());
-        return b;
-    }
-
     protected void defineTableColumns() {
         addContainerProperty(ICON, Resource.class, null, "", null, ALIGN_CENTER);
         addContainerProperty(OBJECT_NAME, String.class, null);
@@ -78,17 +71,23 @@ public abstract class TargetsPanel exten
         setColumnWidth(REGISTRATION_STATE_ICON, ICON_WIDTH);
         setColumnWidth(STORE_STATE_ICON, ICON_WIDTH);
         setColumnWidth(PROVISIONING_STATE_ICON, ICON_WIDTH);
-        
+
         setColumnCollapsible(ICON, false);
         setColumnCollapsible(ACTION_UNLINK, false);
         setColumnCollapsible(ACTION_DELETE, false);
     }
 
     @Override
-    protected boolean doRemoveLeftSideAssociation(StatefulTargetObject object, RepositoryObject other) {
-        List<Distribution2TargetAssociation> associations = object.getAssociationsWith((DistributionObject) other);
+    protected boolean doCreateLeftSideAssociation(DistributionObject distribution, StatefulTargetObject target) {
+        m_associationManager.createDistribution2TargetAssociation(distribution, target);
+        return true;
+    }
+
+    @Override
+    protected boolean doRemoveLeftSideAssociation(DistributionObject distribution, StatefulTargetObject target) {
+        List<Distribution2TargetAssociation> associations = target.getAssociationsWith(distribution);
         for (Distribution2TargetAssociation association : associations) {
-            m_associationRemover.removeAssociation(association);
+            m_associationManager.removeAssociation(association);
         }
         return true;
     }
@@ -131,10 +130,28 @@ public abstract class TargetsPanel exten
         item.getItemProperty(REGISTRATION_STATE_ICON).setValue(getRegistrationStateIcon(target));
         item.getItemProperty(STORE_STATE_ICON).setValue(getStoreStateIcon(target));
         item.getItemProperty(PROVISIONING_STATE_ICON).setValue(getProvisioningStateIcon(target));
-        item.getItemProperty(ACTION_UNLINK).setValue(createUnlinkButton(target));
+        item.getItemProperty(ACTION_UNLINK).setValue(new RemoveLinkButton(target));
         item.getItemProperty(ACTION_DELETE).setValue(createRemoveItemButton(target));
     }
 
+    /**
+     * 
+     * @param entity
+     * @return
+     */
+    private StatefulTargetObject asStatefulTargetObject(RepositoryObject entity) {
+        if (entity instanceof StatefulTargetObject) {
+            return (StatefulTargetObject) entity;
+        }
+        return getFromId(((TargetObject) entity).getDefinition());
+    }
+
+    private RemoveItemButton createRemoveItemButton(StatefulTargetObject object) {
+        RemoveItemButton b = new RemoveItemButton(object);
+        b.setEnabled(object.isRegistered());
+        return b;
+    }
+
     private Embedded getProvisioningStateIcon(StatefulTargetObject object) {
         String name = object.getProvisioningState().name();
         Resource res = createIconResource("target_provisioning_" + name);
@@ -160,16 +177,4 @@ public abstract class TargetsPanel exten
         Resource res = createIconResource("target_store_" + name);
         return createIcon(name, res);
     }
-
-    /**
-     * 
-     * @param entity
-     * @return
-     */
-    private StatefulTargetObject asStatefulTargetObject(RepositoryObject entity) {
-        if (entity instanceof StatefulTargetObject) {
-            return (StatefulTargetObject) entity;
-        }
-        return getFromId(((TargetObject) entity).getDefinition());
-    }
 }