diff options
author | Artur Signell <artur.signell@itmill.com> | 2011-11-04 09:01:09 +0000 |
---|---|---|
committer | Artur Signell <artur.signell@itmill.com> | 2011-11-04 09:01:09 +0000 |
commit | a4d0d363bb6b8d9d2d5eeebe12ee39e97483d4e8 (patch) | |
tree | d091e4c14600038a7a43234d97dd742eb964201c | |
parent | 9d528ff42cc42673124db07173163b900b638e20 (diff) | |
download | vaadin-framework-a4d0d363bb6b8d9d2d5eeebe12ee39e97483d4e8.tar.gz vaadin-framework-a4d0d363bb6b8d9d2d5eeebe12ee39e97483d4e8.zip |
#7780 Don't do partial repaints if the item set has changed during an expand or collapse
svn changeset:21901/svn branch:6.7
3 files changed, 242 insertions, 114 deletions
diff --git a/src/com/vaadin/ui/TreeTable.java b/src/com/vaadin/ui/TreeTable.java index aa72793636..9cba7362ac 100644 --- a/src/com/vaadin/ui/TreeTable.java +++ b/src/com/vaadin/ui/TreeTable.java @@ -11,6 +11,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.logging.Logger; import com.google.gwt.user.client.ui.Tree; import com.vaadin.data.Container; @@ -50,6 +51,9 @@ import com.vaadin.ui.treetable.HierarchicalContainerOrderedWrapper; @ClientWidget(VTreeTable.class) public class TreeTable extends Table implements Hierarchical { + private static final Logger logger = Logger.getLogger(TreeTable.class + .getName()); + private interface ContainerStrategy extends Serializable { public int size(); @@ -220,6 +224,9 @@ public class TreeTable extends Table implements Hierarchical { boolean removed = openItems.remove(itemId); if (!removed) { openItems.add(itemId); + logger.finest("Item " + itemId + " is now expanded"); + } else { + logger.finest("Item " + itemId + " is now collapsed"); } clearPreorderCache(); } @@ -312,6 +319,16 @@ public class TreeTable extends Table implements Hierarchical { private ContainerStrategy cStrategy; private Object focusedRowId = null; private Object hierarchyColumnId; + + /** + * The item id that was expanded or collapsed during this request. Reset at + * the end of paint and only used for determining if a partial or full paint + * should be done. + * + * Can safely be reset to null whenever a change occurs that would prevent a + * partial update from rendering the correct result, e.g. rows added or + * removed during an expand operation. + */ private Object toggledItemId; private boolean animationsEnabled; private boolean clearFocusedRowPending; @@ -361,6 +378,7 @@ public class TreeTable extends Table implements Hierarchical { if (variables.containsKey("toggleCollapsed")) { String object = (String) variables.get("toggleCollapsed"); Object itemId = itemIdMapper.get(object); + toggledItemId = itemId; toggleChildVisibility(itemId); if (variables.containsKey("selectCollapsed")) { // ensure collapsed is selected unless opened with selection @@ -497,7 +515,6 @@ public class TreeTable extends Table implements Hierarchical { // ensure that page still has first item in page, DON'T clear the // caches. setCurrentPageFirstItemIndex(getCurrentPageFirstItemIndex(), false); - toggledItemId = itemId; requestRepaint(); if (isCollapsed(itemId)) { @@ -535,6 +552,9 @@ public class TreeTable extends Table implements Hierarchical { @Override public void containerItemSetChange( com.vaadin.data.Container.ItemSetChangeEvent event) { + // Can't do partial repaints if items are added or removed during the + // expand/collapse request + toggledItemId = null; getContainerStrategy().containerItemSetChange(event); super.containerItemSetChange(event); } diff --git a/tests/testbench/com/vaadin/tests/components/treetable/DynamicallyModified.html b/tests/testbench/com/vaadin/tests/components/treetable/DynamicallyModified.html new file mode 100644 index 0000000000..01bbb75361 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/treetable/DynamicallyModified.html @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.treetable.DynamicallyModified?restartApplication</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>initial</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreetableDynamicallyModified::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTreeTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]/domChild[0]</td> + <td>47,5</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>proj1-collapsed</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreetableDynamicallyModified::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTreeTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]/domChild[0]</td> + <td>48,8</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>proj1-two-children</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreetableDynamicallyModified::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTreeTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[5]/domChild[0]/domChild[0]/domChild[0]</td> + <td>49,7</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>proj2-collapsed</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreetableDynamicallyModified::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTreeTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[5]/domChild[0]/domChild[0]/domChild[0]</td> + <td>47,7</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>proj2-three-children</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreetableDynamicallyModified::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTreeTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[5]/domChild[0]/domChild[0]/domChild[0]</td> + <td>45,4</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreetableDynamicallyModified::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTreeTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[5]/domChild[0]/domChild[0]/domChild[0]</td> + <td>45,4</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreetableDynamicallyModified::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTreeTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]/domChild[0]</td> + <td>48,6</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreetableDynamicallyModified::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTreeTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]/domChild[0]</td> + <td>48,6</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>proj1-one-child-proj2-four-children</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/treetable/DynamicallyModified.java b/tests/testbench/com/vaadin/tests/components/treetable/DynamicallyModified.java index db4e93b1f6..3d76211154 100644 --- a/tests/testbench/com/vaadin/tests/components/treetable/DynamicallyModified.java +++ b/tests/testbench/com/vaadin/tests/components/treetable/DynamicallyModified.java @@ -1,113 +1,129 @@ -package com.vaadin.tests.components.treetable; - -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; - -import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Tree; -import com.vaadin.ui.Tree.CollapseEvent; -import com.vaadin.ui.Tree.ExpandEvent; -import com.vaadin.ui.TreeTable; - -public class DynamicallyModified extends TestBase implements - Tree.ExpandListener, Tree.CollapseListener { - protected static final String NAME_PROPERTY = "Name"; - protected static final String HOURS_PROPERTY = "Hours done"; - protected static final String MODIFIED_PROPERTY = "Last Modified"; - - protected TreeTable treetable; - - @Override - protected void setup() { - getLayout().setWidth("100%"); - - // Calendar - Calendar cal = Calendar.getInstance(); - cal.set(2011, 10, 30, 14, 40, 26); - - // Create the treetable - treetable = new TreeTable(); - treetable.setWidth("100%"); - treetable.addListener((Tree.ExpandListener) this); - treetable.addListener((Tree.CollapseListener) this); - - addComponent(treetable); - - // Add Table columns - treetable.addContainerProperty(NAME_PROPERTY, String.class, ""); - treetable.addContainerProperty(HOURS_PROPERTY, Integer.class, 0); - treetable.addContainerProperty(MODIFIED_PROPERTY, Date.class, - cal.getTime()); - - // Populate table - Object allProjects = treetable.addItem(new Object[] { "All Projects", - 18, cal.getTime() }, null); - Object year2010 = treetable.addItem( - new Object[] { "Year 2010", 18, cal.getTime() }, null); - Object customerProject1 = treetable.addItem(new Object[] { - "Customer Project 1", 13, cal.getTime() }, null); - Object customerProject1Implementation = treetable.addItem(new Object[] { - "Implementation", 5, cal.getTime() }, null); - Object customerProject1Planning = treetable.addItem(new Object[] { - "Planning", 2, cal.getTime() }, null); - Object customerProject1Prototype = treetable.addItem(new Object[] { - "Prototype", 5, cal.getTime() }, null); - Object customerProject2 = treetable.addItem(new Object[] { - "Customer Project 2", 5, cal.getTime() }, null); - Object customerProject2Planning = treetable.addItem(new Object[] { - "Planning", 5, cal.getTime() }, null); - - // Set hierarchy - treetable.setParent(year2010, allProjects); - treetable.setParent(customerProject1, year2010); - treetable.setParent(customerProject1Implementation, customerProject1); - treetable.setParent(customerProject1Planning, customerProject1); - treetable.setParent(customerProject1Prototype, customerProject1); - treetable.setParent(customerProject2, year2010); - treetable.setParent(customerProject2Planning, customerProject2); - - // Disallow children from leaves - treetable.setChildrenAllowed(customerProject1Implementation, false); - treetable.setChildrenAllowed(customerProject1Planning, false); - treetable.setChildrenAllowed(customerProject1Prototype, false); - treetable.setChildrenAllowed(customerProject2Planning, false); - - // Expand all - treetable.setCollapsed(allProjects, false); - treetable.setCollapsed(year2010, false); - treetable.setCollapsed(customerProject1, false); - treetable.setCollapsed(customerProject2, false); - } - - @Override - protected String getDescription() { - return "Expanding and collapsing nodes should actually expand and collapse them even when modifying the container in a collapse listener."; - } - - @Override - protected Integer getTicketNumber() { - return 7780; - } - - public void nodeExpand(ExpandEvent event) { - - } - - public void nodeCollapse(CollapseEvent event) { - - Collection<Object> childs = (Collection<Object>) treetable - .getChildren(event.getItemId()); - - if (childs == null) { - return; - } - Object[] arr = childs.toArray(); - - for (Object obj : arr) { - System.out.println("remove " + obj.toString()); - treetable.removeItem(obj); - } - - } -} +package com.vaadin.tests.components.treetable;
+
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Tree;
+import com.vaadin.ui.Tree.CollapseEvent;
+import com.vaadin.ui.Tree.ExpandEvent;
+import com.vaadin.ui.TreeTable;
+
+public class DynamicallyModified extends TestBase implements
+ Tree.ExpandListener, Tree.CollapseListener {
+ protected static final String NAME_PROPERTY = "Name";
+ protected static final String HOURS_PROPERTY = "Hours done";
+ protected static final String MODIFIED_PROPERTY = "Last Modified";
+
+ protected TreeTable treetable;
+
+ @Override
+ protected void setup() {
+ getLayout().setWidth("100%");
+
+ // Calendar
+ Calendar cal = Calendar.getInstance();
+ cal.set(2011, 10, 30, 14, 40, 26);
+
+ // Create the treetable
+ treetable = new TreeTable();
+ treetable.setWidth("100%");
+ treetable.addListener((Tree.ExpandListener) this);
+ treetable.addListener((Tree.CollapseListener) this);
+
+ addComponent(treetable);
+
+ // Add Table columns
+ treetable.addContainerProperty(NAME_PROPERTY, String.class, "");
+ treetable.addContainerProperty(HOURS_PROPERTY, Integer.class, 0);
+ treetable.addContainerProperty(MODIFIED_PROPERTY, Date.class,
+ cal.getTime());
+
+ // Populate table
+ Object allProjects = treetable.addItem(new Object[] { "All Projects",
+ 18, cal.getTime() }, null);
+ Object year2010 = treetable.addItem(
+ new Object[] { "Year 2010", 18, cal.getTime() }, null);
+ Object customerProject1 = treetable.addItem(new Object[] {
+ "Customer Project 1", 13, cal.getTime() }, null);
+ Object customerProject1Implementation = treetable.addItem(new Object[] {
+ "Implementation", 5, cal.getTime() }, null);
+ Object customerProject1Planning = treetable.addItem(new Object[] {
+ "Planning", 2, cal.getTime() }, null);
+ Object customerProject1Prototype = treetable.addItem(new Object[] {
+ "Prototype", 5, cal.getTime() }, null);
+ Object customerProject2 = treetable.addItem(new Object[] {
+ "Customer Project 2", 5, cal.getTime() }, null);
+ Object customerProject2Planning = treetable.addItem(new Object[] {
+ "Planning", 5, cal.getTime() }, null);
+
+ // Set hierarchy
+ treetable.setParent(year2010, allProjects);
+ treetable.setParent(customerProject1, year2010);
+ treetable.setParent(customerProject1Implementation, customerProject1);
+ treetable.setParent(customerProject1Planning, customerProject1);
+ treetable.setParent(customerProject1Prototype, customerProject1);
+ treetable.setParent(customerProject2, year2010);
+ treetable.setParent(customerProject2Planning, customerProject2);
+
+ // Disallow children from leaves
+ treetable.setChildrenAllowed(customerProject1Implementation, false);
+ treetable.setChildrenAllowed(customerProject1Planning, false);
+ treetable.setChildrenAllowed(customerProject1Prototype, false);
+ treetable.setChildrenAllowed(customerProject2Planning, false);
+
+ // Expand all
+ treetable.setCollapsed(allProjects, false);
+ treetable.setCollapsed(year2010, false);
+ treetable.setCollapsed(customerProject1, false);
+ treetable.setCollapsed(customerProject2, false);
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Collaps 'Customer Project 1' will cause the first child if it to be removed. Expanding 'Custom Project 2' will cause a new child to be added. These events should be rendered correctly.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 7780;
+ }
+
+ private int newChild = 1;
+
+ public void nodeExpand(ExpandEvent event) {
+ Object expandedItemId = event.getItemId();
+ // 7 == "Customer Project 1"
+ if (expandedItemId != Integer.valueOf(7)) {
+ return;
+ }
+ Object newChildId = treetable.addItem(new Object[] {
+ "New child " + newChild++, 5, new Date() }, null);
+ treetable.setParent(newChildId, expandedItemId);
+ treetable.setChildrenAllowed(newChildId, false);
+ }
+
+ public void nodeCollapse(CollapseEvent event) {
+
+ Object collapsedItemId = event.getItemId();
+
+ // 3 == "Customer Project 1"
+ if (collapsedItemId != Integer.valueOf(3)) {
+ return;
+ }
+ @SuppressWarnings("unchecked")
+ Collection<Object> childs = (Collection<Object>) treetable
+ .getChildren(event.getItemId());
+
+ if (childs == null) {
+ return;
+ }
+ Object[] arr = childs.toArray();
+
+ if (arr.length > 0) {
+ treetable.removeItem(arr[0]);
+ }
+
+ }
+}
\ No newline at end of file |