]> source.dussan.org Git - vaadin-framework.git/commitdiff
Separated Component.isEnabled/isVisible from Connector enabled state.
authorArtur Signell <artur@vaadin.com>
Wed, 14 Mar 2012 07:52:50 +0000 (09:52 +0200)
committerArtur Signell <artur@vaadin.com>
Wed, 14 Mar 2012 14:01:09 +0000 (16:01 +0200)
Connector.isConnectorEnabled determines if the Connector can receive
messages from its counter part. Component isEnabled/isVisible only
returns the state of the component. Made Table implement HasComponents.

13 files changed:
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
src/com/vaadin/terminal/gwt/client/Connector.java
src/com/vaadin/terminal/gwt/client/ConnectorMap.java
src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java
src/com/vaadin/terminal/gwt/client/ui/TableConnector.java
src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
src/com/vaadin/ui/AbstractComponent.java
src/com/vaadin/ui/AbstractSelect.java
src/com/vaadin/ui/Component.java
src/com/vaadin/ui/Root.java
src/com/vaadin/ui/Table.java
tests/testbench/com/vaadin/tests/components/table/TableWithChildComponents.java [new file with mode: 0644]

index a7362cbb8c0064ae2861b56df9bd51c655d65b35..66dcd069ab130932ef8d9b2b31c46e12116f91ff 100644 (file)
@@ -1092,6 +1092,7 @@ public class ApplicationConnection {
             }
 
             private void unregisterRemovedConnectors() {
+                int unregistered = 0;
                 List<ServerConnector> currentConnectors = new ArrayList<ServerConnector>(
                         connectorMap.getConnectors());
                 for (ServerConnector c : currentConnectors) {
@@ -1104,6 +1105,7 @@ public class ApplicationConnection {
                             // children. The RootConnector should never be
                             // unregistered even though it has no parent.
                             connectorMap.unregisterConnector(cc);
+                            unregistered++;
                         } else if (cc.getParent() != null
                                 && !cc.getParent().getChildren().contains(cc)) {
                             VConsole.error("ERROR: Connector is connected to a parent but the parent does not contain the connector");
@@ -1112,6 +1114,7 @@ public class ApplicationConnection {
 
                 }
 
+                VConsole.log("* Unregistered " + unregistered + " connectors");
             }
 
             private void createConnectorsIfNeeded(ValueMap json) {
index 45abe100078b4ff147a8f43c0ff8ea0aa9c84f47..59bcdd6bfe030dac27fb98c48c6ba31276fce9a9 100644 (file)
@@ -29,4 +29,11 @@ public interface Connector {
      */
     public String getConnectorId();
 
+    /**
+     * Checks if the communicator is enabled. An enabled communicator is allowed
+     * to receive messages from its counter-part.
+     * 
+     * @return true if the connector can receive messages, false otherwise
+     */
+    public boolean isConnectorEnabled();
 }
index f5ec33de5fee336fe5fcea17b2509384e28b8300..79b16be3a74109a17674bb45563edd213695fd79 100644 (file)
@@ -7,12 +7,10 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Element;
-import com.google.gwt.user.client.ui.HasWidgets;
 import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.terminal.Paintable;
 import com.vaadin.terminal.gwt.client.RenderInformation.Size;
@@ -218,39 +216,6 @@ public class ConnectorMap {
         return result.toArray(new ComponentConnector[result.size()]);
     }
 
-    /**
-     * Unregisters the child connectors for the given container recursively.
-     * 
-     * Use when after removing a connector that contains other connectors. Does
-     * not unregister the given container itself. Does not actually remove the
-     * widgets from the DOM.
-     * 
-     * @see #unregisterConnector(ServerConnector)
-     * @param container
-     *            The container that contains the connectors that should be
-     *            unregistered
-     * @deprecated Only here for now to support the broken VScrollTable behavior
-     */
-    @Deprecated
-    public void unregisterChildConnectors(HasWidgets container) {
-        // FIXME: This should be based on the paintable hierarchy
-        final Iterator<Widget> it = container.iterator();
-        while (it.hasNext()) {
-            final Widget w = it.next();
-            ComponentConnector p = getConnector(w);
-            if (p != null) {
-                // This will unregister the paintable and all its children
-                idToComponentDetail.remove(p.getConnectorId());
-                idToConnector.remove(p.getConnectorId());
-            }
-
-            if (w instanceof HasWidgets) {
-                // For normal widget containers, unregister the children
-                unregisterChildConnectors((HasWidgets) w);
-            }
-        }
-    }
-
     /**
      * FIXME: Should not be here
      * 
index 8ba2bb4d31060939e6550f4dc7762fcafb4a159f..84ccfeadaab4aa0f9bf9312f0e4049e6449f35b2 100644 (file)
@@ -123,4 +123,13 @@ public abstract class AbstractConnector implements ServerConnector {
         return (Collection<T>) rpcImplementations.get(rpcInterfaceId);
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.terminal.gwt.client.Connector#isConnectorEnabled()
+     */
+    public boolean isConnectorEnabled() {
+        // Client side can always receive message from the server
+        return true;
+    }
 }
index 0d17a7ccc248e1947e41f1b1c30db981338052b7..eae0cd61eee55931f1d92b3d118303a73d6b3525 100644 (file)
@@ -182,7 +182,6 @@ public class TableConnector extends AbstractComponentContainerConnector
         }
 
         getWidget().hideScrollPositionAnnotation();
-        getWidget().purgeUnregistryBag();
 
         // selection is no in sync with server, avoid excessive server visits by
         // clearing to flag used during the normal operation
index 9166ffdf9fb5a165dfd48ad15c6f86a2dbf86f3a..e589b8eead47bd67fd743883abe2e82bc7501fb2 100644 (file)
@@ -430,7 +430,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
      */
     boolean recalcWidths = false;
 
-    private final ArrayList<Panel> lazyUnregistryBag = new ArrayList<Panel>();
     boolean rendering = false;
     private boolean hasFocus = false;
     private int dragmode;
@@ -826,7 +825,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
     void initializeRows(UIDL uidl, UIDL rowData) {
         if (scrollBody != null) {
             scrollBody.removeFromParent();
-            lazyUnregistryBag.add(scrollBody);
         }
         scrollBody = createScrollBody();
 
@@ -1106,19 +1104,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
         }
     }
 
-    /**
-     * Unregisters Paintables in "trashed" HasWidgets (IScrollTableBodys or
-     * IScrollTableRows). This is done lazily as Table must survive from
-     * "subtreecaching" logic.
-     */
-    void purgeUnregistryBag() {
-        for (Iterator<Panel> iterator = lazyUnregistryBag.iterator(); iterator
-                .hasNext();) {
-            ConnectorMap.get(client).unregisterChildConnectors(iterator.next());
-        }
-        lazyUnregistryBag.clear();
-    }
-
     void updateActionMap(UIDL mainUidl) {
         UIDL actionsUidl = mainUidl.getChildByTagName("actions");
         if (actionsUidl == null) {
@@ -4136,7 +4121,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
                 Element td = toBeRemoved.getElement().getChild(i).cast();
                 client.registerTooltip(VScrollTable.this, td, null);
             }
-            lazyUnregistryBag.add(toBeRemoved);
             tBodyElement.removeChild(toBeRemoved.getElement());
             orphan(toBeRemoved);
             renderedRows.remove(index);
index c509cbb33e640a85bdb394ff2ca0f89818d726bf..fc5f79a2e7de3f3ef9e1f77782b2b6240ab6716c 100644 (file)
@@ -61,6 +61,7 @@ import com.vaadin.terminal.VariableOwner;
 import com.vaadin.terminal.WrappedRequest;
 import com.vaadin.terminal.WrappedResponse;
 import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Connector;
 import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
 import com.vaadin.terminal.gwt.client.communication.SharedState;
 import com.vaadin.terminal.gwt.server.BootstrapHandler.BootstrapContext;
@@ -951,7 +952,7 @@ public abstract class AbstractCommunicationManager implements
                     JSONArray children = new JSONArray();
 
                     for (Component child : getChildComponents(parent)) {
-                        if (child.isVisible()) {
+                        if (isVisible(child)) {
                             String childConnectorId = getPaintableId(child);
                             children.put(childConnectorId);
                         }
@@ -1160,6 +1161,15 @@ public abstract class AbstractCommunicationManager implements
         }
     }
 
+    private boolean isVisible(Component child) {
+        HasComponents parent = (HasComponents) child.getParent();
+        if (parent == null || !child.isVisible()) {
+            return child.isVisible();
+        }
+
+        return parent.isComponentVisible(child) && isVisible(parent);
+    }
+
     private static class NullIterator<E> implements Iterator<E> {
 
         public boolean hasNext() {
@@ -1458,7 +1468,15 @@ public abstract class AbstractCommunicationManager implements
                 final VariableOwner owner = getVariableOwner(invocation
                         .getConnectorId());
 
-                if (owner != null && owner.isEnabled()) {
+                boolean connectorEnabled;
+                if (owner instanceof Connector) {
+                    connectorEnabled = ((Connector) owner).isConnectorEnabled();
+                } else {
+                    // TODO Remove
+                    connectorEnabled = owner.isEnabled();
+                }
+
+                if (owner != null && connectorEnabled) {
                     VariableChange change = new VariableChange(invocation);
 
                     // TODO could optimize with a single value map if only one
@@ -2050,7 +2068,7 @@ public abstract class AbstractCommunicationManager implements
                     if (componentsRoot != r) {
                         resultset.remove(p);
                     } else if (component.getParent() != null
-                            && !component.getParent().isVisible()) {
+                            && !isVisible(component.getParent())) {
                         /*
                          * Do not return components in an invisible subtree.
                          * 
index b9e8f1836817b03dab37fc6d271ac0874a93afb6..9665cf011affeb1f5739f90c07b69db5090480a1 100644 (file)
@@ -68,7 +68,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
     /**
      * The container this component resides in.
      */
-    private Component parent = null;
+    private HasComponents parent = null;
 
     /**
      * The EventRouter used for the event model.
@@ -360,17 +360,18 @@ public abstract class AbstractComponent implements Component, MethodEventSource
     }
 
     /*
-     * Tests if the component is enabled or not. Don't add a JavaDoc comment
-     * here, we use the default documentation from implemented interface.
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.ui.Component#isEnabled()
      */
     public boolean isEnabled() {
-        return getState().isEnabled()
-                && (getParent() == null || getParent().isEnabled());
+        return getState().isEnabled();
     }
 
     /*
-     * Enables or disables the component. Don't add a JavaDoc comment here, we
-     * use the default documentation from implemented interface.
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.ui.Component#setEnabled(boolean)
      */
     public void setEnabled(boolean enabled) {
         if (getState().isEnabled() != enabled) {
@@ -379,6 +380,29 @@ public abstract class AbstractComponent implements Component, MethodEventSource
         }
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.terminal.gwt.client.Connector#isConnectorEnabled()
+     */
+    public boolean isConnectorEnabled() {
+        if (getParent() == null) {
+            // No parent -> the component cannot receive updates from the client
+            return false;
+        } else {
+            boolean thisEnabledAndVisible = isEnabled() && isVisible();
+            if (!thisEnabledAndVisible) {
+                return false;
+            }
+
+            if (!getParent().isConnectorEnabled()) {
+                return false;
+            }
+
+            return getParent().isComponentVisible(this);
+        }
+    }
+
     /*
      * Tests if the component is in the immediate mode. Don't add a JavaDoc
      * comment here, we use the default documentation from implemented
@@ -409,12 +433,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
      * @see com.vaadin.ui.Component#isVisible()
      */
     public boolean isVisible() {
-        if (getParent() == null) {
-            return getState().isVisible();
-        } else {
-            return getState().isVisible() && getParent().isVisible()
-                    && ((HasComponents) getParent()).isComponentVisible(this);
-        }
+        return getState().isVisible();
     }
 
     /*
@@ -423,7 +442,6 @@ public abstract class AbstractComponent implements Component, MethodEventSource
      * @see com.vaadin.ui.Component#setVisible(boolean)
      */
     public void setVisible(boolean visible) {
-
         if (getState().isVisible() != visible) {
             getState().setVisible(visible);
             // Instead of requesting repaint normally we
@@ -517,7 +535,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
      * Gets the component's parent component. Don't add a JavaDoc comment here,
      * we use the default documentation from implemented interface.
      */
-    public Component getParent() {
+    public HasComponents getParent() {
         return parent;
     }
 
@@ -525,7 +543,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
      * Sets the parent component. Don't add a JavaDoc comment here, we use the
      * default documentation from implemented interface.
      */
-    public void setParent(Component parent) {
+    public void setParent(HasComponents parent) {
 
         // If the parent is not changed, don't do anything
         if (parent == this.parent) {
@@ -741,7 +759,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
             // Paint the contents of the component
 
             // Only paint content of visible components.
-            if (isVisible()) {
+            if (isVisibleInContext()) {
 
                 if (eventIdentifiers != null) {
                     target.addAttribute("eventListeners",
@@ -763,6 +781,27 @@ public abstract class AbstractComponent implements Component, MethodEventSource
         repaintRequestListenersNotified = false;
     }
 
+    /**
+     * Checks if the component is visible and its parent is visible,
+     * recursively.
+     * <p>
+     * This is only a helper until paint is moved away from this class.
+     * 
+     * @return
+     */
+    @Deprecated
+    protected boolean isVisibleInContext() {
+        HasComponents p = getParent();
+        while (p != null) {
+            if (!p.isVisible()) {
+                return false;
+            }
+            p = p.getParent();
+        }
+        // All parents visible, return this state
+        return isVisible();
+    }
+
     /**
      * Build CSS compatible string representation of height.
      * 
index 47f132aa77f3b1105482ce99263dd148d12020ed..6a6c4528963fc1e296ee31640e914de390b68d92 100644 (file)
@@ -35,6 +35,7 @@ import com.vaadin.terminal.Resource;
 import com.vaadin.terminal.gwt.client.ui.dd.VIsOverId;
 import com.vaadin.terminal.gwt.client.ui.dd.VItemIdIs;
 import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
+import com.vaadin.ui.AbstractSelect.ItemCaptionMode;
 
 /**
  * <p>
@@ -581,7 +582,7 @@ public abstract class AbstractSelect extends AbstractField<Object> implements
      * to the terminal or null if no items is visible.
      */
     public Collection<?> getVisibleItemIds() {
-        if (isVisible()) {
+        if (isVisibleInContext()) {
             return getItemIds();
         }
         return null;
index d3efb74118972584aeb9ef9be91fb5c4f9cf27ac..6ca4d5e2860cd02e01f7e5c8bdf484abe4abe150 100644 (file)
@@ -205,8 +205,14 @@ public interface Component extends Connector, Paintable, VariableOwner,
      * component are also disabled. Components are enabled by default.
      * 
      * <p>
-     * As a security feature, all variable change events for disabled components
-     * are blocked on the server-side.
+     * As a security feature, all updates for disabled components are blocked on
+     * the server-side.
+     * </p>
+     * 
+     * <p>
+     * Note that this method only returns the status of the component and does
+     * not take parents into account. Even though this method returns true the
+     * component can be disabled to the user if a parent is disabled.
      * </p>
      * 
      * @return <code>true</code> if the component and its parent are enabled,
@@ -219,9 +225,6 @@ public interface Component extends Connector, Paintable, VariableOwner,
      * Enables or disables the component. The user can not interact disabled
      * components, which are shown with a style that indicates the status,
      * usually shaded in light gray color. Components are enabled by default.
-     * Children of a disabled component are automatically disabled; if a child
-     * component is explicitly set as disabled, changes in the disabled status
-     * of its parents do not change its status.
      * 
      * <pre>
      * Button enabled = new Button(&quot;Enabled&quot;);
@@ -251,27 +254,22 @@ public interface Component extends Connector, Paintable, VariableOwner,
      * 
      * <p>
      * Visible components are drawn in the user interface, while invisible ones
-     * are not. The effect is not merely a cosmetic CSS change, but the entire
-     * HTML element will be empty. Making a component invisible through this
-     * property can alter the positioning of other components.
-     * </p>
-     * 
-     * <p>
-     * A component is visible only if all its parents are also visible. Notice
-     * that if a child component is explicitly set as invisible, changes in the
-     * visibility status of its parents do not change its status.
+     * are not. The effect is not merely a cosmetic CSS change - no information
+     * about an invisible component will be sent to the client. The effect is
+     * thus the same as removing the component from its parent. Making a
+     * component invisible through this property can alter the positioning of
+     * other components.
      * </p>
      * 
      * <p>
-     * This method does not check whether the component is attached (see
-     * {@link #attach()}). The component and all its parents may be considered
-     * "visible", but not necessarily attached to application. To test if
-     * component will actually be drawn, check both its visibility and that
-     * {@link #getApplication()} does not return {@code null}.
+     * A component is visible only if all its parents are also visible. This is
+     * not checked by this method though, so even if this method returns true,
+     * the component can be hidden from the user because a parent is set to
+     * invisible.
      * </p>
      * 
-     * @return <code>true</code> if the component is visible in the user
-     *         interface, <code>false</code> if not
+     * @return <code>true</code> if the component has been set to be visible in
+     *         the user interface, <code>false</code> if not
      * @see #setVisible(boolean)
      * @see #attach()
      */
@@ -282,8 +280,9 @@ public interface Component extends Connector, Paintable, VariableOwner,
      * 
      * <p>
      * Visible components are drawn in the user interface, while invisible ones
-     * are not. The effect is not merely a cosmetic CSS change, but the entire
-     * HTML element will be empty.
+     * are not. The effect is not merely a cosmetic CSS change - no information
+     * about an invisible component will be sent to the client. The effect is
+     * thus the same as removing the component from its parent.
      * </p>
      * 
      * <pre>
@@ -318,7 +317,7 @@ public interface Component extends Connector, Paintable, VariableOwner,
      * @return the parent component
      * @see #setParent(Component)
      */
-    public Component getParent();
+    public HasComponents getParent();
 
     /**
      * Sets the parent component of the component.
@@ -349,7 +348,7 @@ public interface Component extends Connector, Paintable, VariableOwner,
      *             if a parent is given even though the component already has a
      *             parent
      */
-    public void setParent(Component parent);
+    public void setParent(HasComponents parent);
 
     /**
      * Tests whether the component is in the read-only mode. The user can not
index 47f962bf3d77cde5d6a775d0e03419087931afa2..42d921d93fc7db15ff3d1eda64ec5435b268a7a4 100644 (file)
@@ -1562,4 +1562,9 @@ public abstract class Root extends AbstractComponentContainer implements
         }
     }
 
+    @Override
+    public boolean isConnectorEnabled() {
+        // TODO How can a Root be invisible? What does it mean?
+        return isVisible() && isEnabled();
+    }
 }
index c9d4ca63a368db336b1dff31dfb21b7cd59b90ee..52981b875f757283035bf24a17b0a7f279dea732 100644 (file)
@@ -77,7 +77,7 @@ import com.vaadin.terminal.gwt.client.ui.dd.VLazyInitItemIdentifiers;
 @ClientWidget(TableConnector.class)
 public class Table extends AbstractSelect implements Action.Container,
         Container.Ordered, Container.Sortable, ItemClickSource,
-        ItemClickNotifier, DragSource, DropTarget {
+        ItemClickNotifier, DragSource, DropTarget, HasComponents {
 
     private static final Logger logger = Logger
             .getLogger(Table.class.getName());
@@ -5288,11 +5288,23 @@ public class Table extends AbstractSelect implements Action.Container,
 
     @Override
     public void setVisible(boolean visible) {
-        if (!isVisible() && visible) {
+        if (!isVisibleInContext() && visible) {
             // We need to ensure that the rows are sent to the client when the
             // Table is made visible if it has been rendered as invisible.
             setRowCacheInvalidated(true);
         }
         super.setVisible(visible);
     }
+
+    public Iterator<Component> iterator() {
+        return getComponentIterator();
+    }
+
+    public Iterator<Component> getComponentIterator() {
+        return visibleComponents.iterator();
+    }
+
+    public boolean isComponentVisible(Component childComponent) {
+        return true;
+    }
 }
diff --git a/tests/testbench/com/vaadin/tests/components/table/TableWithChildComponents.java b/tests/testbench/com/vaadin/tests/components/table/TableWithChildComponents.java
new file mode 100644 (file)
index 0000000..1d1c162
--- /dev/null
@@ -0,0 +1,66 @@
+package com.vaadin.tests.components.table;
+
+import com.vaadin.data.Item;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.tests.util.Log;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.NativeButton;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Table.ColumnGenerator;
+
+public class TableWithChildComponents extends TestBase implements ClickListener {
+
+    private static final String COL2 = "Column 2 - generated";
+    private static final String COL1 = "Column 1 - components";
+    private Log log = new Log(10);
+
+    @Override
+    protected void setup() {
+        Table table = new Table();
+        table.setWidth("500px");
+        table.setPageLength(10);
+        table.addContainerProperty(COL1, Component.class, null);
+        table.addContainerProperty(COL2, Component.class, null);
+
+        table.addGeneratedColumn(COL2, new ColumnGenerator() {
+
+            public Object generateCell(Table source, Object itemId,
+                    Object columnId) {
+                return new Button(
+                        "Item id: " + itemId + " column: " + columnId,
+                        TableWithChildComponents.this);
+            }
+        });
+
+        for (int i = 0; i < 100; i++) {
+            Item item = table.addItem("Row " + i);
+            item.getItemProperty(COL1).setValue(
+                    new NativeButton("Row " + i + " native", this));
+        }
+
+        addComponent(table);
+        addComponent(log);
+
+    }
+
+    @Override
+    protected String getDescription() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected Integer getTicketNumber() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public void buttonClick(ClickEvent event) {
+        log.log("Click on " + event.getButton().getCaption());
+
+    }
+
+}