Change-Id: Ifeb081086a4231f75f07f4d26c56ec22e72ce5d1tags/7.6.0.alpha4
@@ -69,6 +69,7 @@ import com.vaadin.shared.util.SharedUtil; | |||
import com.vaadin.ui.declarative.DesignAttributeHandler; | |||
import com.vaadin.ui.declarative.DesignContext; | |||
import com.vaadin.ui.declarative.DesignException; | |||
import com.vaadin.util.ReflectTools; | |||
/** | |||
* <p> | |||
@@ -1310,6 +1311,8 @@ public class Table extends AbstractSelect implements Action.Container, | |||
* the desired collapsedness. | |||
* @throws IllegalStateException | |||
* if column collapsing is not allowed | |||
* @throws IllegalArgumentException | |||
* if the property id does not exist | |||
*/ | |||
public void setColumnCollapsed(Object propertyId, boolean collapsed) | |||
throws IllegalStateException { | |||
@@ -1319,11 +1322,19 @@ public class Table extends AbstractSelect implements Action.Container, | |||
if (collapsed && noncollapsibleColumns.contains(propertyId)) { | |||
throw new IllegalStateException("The column is noncollapsible!"); | |||
} | |||
if (!getContainerPropertyIds().contains(propertyId)) { | |||
throw new IllegalArgumentException("Property '" + propertyId | |||
+ "' was not found in the container"); | |||
} | |||
if (collapsed) { | |||
collapsedColumns.add(propertyId); | |||
if (collapsedColumns.add(propertyId)) { | |||
fireColumnCollapseEvent(propertyId); | |||
} | |||
} else { | |||
collapsedColumns.remove(propertyId); | |||
if (collapsedColumns.remove(propertyId)) { | |||
fireColumnCollapseEvent(propertyId); | |||
} | |||
} | |||
// Assures the visual refresh | |||
@@ -3182,6 +3193,10 @@ public class Table extends AbstractSelect implements Action.Container, | |||
} | |||
} | |||
private void fireColumnCollapseEvent(Object propertyId) { | |||
fireEvent(new ColumnCollapseEvent(this, propertyId)); | |||
} | |||
private void fireColumnResizeEvent(Object propertyId, int previousWidth, | |||
int currentWidth) { | |||
/* | |||
@@ -5741,6 +5756,53 @@ public class Table extends AbstractSelect implements Action.Container, | |||
public void columnReorder(ColumnReorderEvent event); | |||
} | |||
/** | |||
* This event is fired when the collapse state of a column changes | |||
*/ | |||
public static class ColumnCollapseEvent extends Component.Event { | |||
public static final Method METHOD = ReflectTools.findMethod( | |||
ColumnCollapseListener.class, "columnCollapseStateChange", | |||
ColumnCollapseEvent.class); | |||
private Object propertyId; | |||
/** | |||
* Constructor | |||
* | |||
* @param source | |||
* The source of the event | |||
* @param propertyId | |||
* The id of the coumn | |||
*/ | |||
public ColumnCollapseEvent(Component source, Object propertyId) { | |||
super(source); | |||
this.propertyId = propertyId; | |||
} | |||
/** | |||
* Gets the id of the column whose collapse state changed | |||
* | |||
* @return the property id of the column | |||
*/ | |||
public Object getPropertyId() { | |||
return propertyId; | |||
} | |||
} | |||
/** | |||
* Interface for listening to column collapse events. | |||
*/ | |||
public interface ColumnCollapseListener extends Serializable { | |||
/** | |||
* This method is triggered when the collapse state for a column has | |||
* changed | |||
* | |||
* @param event | |||
*/ | |||
public void columnCollapseStateChange(ColumnCollapseEvent event); | |||
} | |||
/** | |||
* Adds a column reorder listener to the Table. A column reorder listener is | |||
* called when a user reorders columns. | |||
@@ -5782,6 +5844,29 @@ public class Table extends AbstractSelect implements Action.Container, | |||
removeColumnReorderListener(listener); | |||
} | |||
/** | |||
* Adds a column collapse listener to the Table. A column collapse listener | |||
* is called when the collapsed state of a column changes. | |||
* | |||
* @param listener | |||
* The listener to attach | |||
*/ | |||
public void addColumnCollapseListener(ColumnCollapseListener listener) { | |||
addListener(TableConstants.COLUMN_COLLAPSE_EVENT_ID, | |||
ColumnCollapseEvent.class, listener, ColumnCollapseEvent.METHOD); | |||
} | |||
/** | |||
* Removes a column reorder listener from the Table. | |||
* | |||
* @param listener | |||
* The listener to remove | |||
*/ | |||
public void removeColumnCollapseListener(ColumnCollapseListener listener) { | |||
removeListener(TableConstants.COLUMN_COLLAPSE_EVENT_ID, | |||
ColumnCollapseEvent.class, listener); | |||
} | |||
/** | |||
* Set the item description generator which generates tooltips for cells and | |||
* rows in the Table |
@@ -23,6 +23,7 @@ public class TableConstants implements Serializable { | |||
public static final String FOOTER_CLICK_EVENT_ID = "handleFooterClick"; | |||
public static final String COLUMN_RESIZE_EVENT_ID = "columnResize"; | |||
public static final String COLUMN_REORDER_EVENT_ID = "columnReorder"; | |||
public static final String COLUMN_COLLAPSE_EVENT_ID = "columnCollapse"; | |||
@Deprecated | |||
public static final String ATTRIBUTE_PAGEBUFFER_FIRST = "pb-ft"; |
@@ -2,21 +2,22 @@ package com.vaadin.tests.components.table; | |||
import com.vaadin.event.Action; | |||
import com.vaadin.event.Action.Handler; | |||
import com.vaadin.tests.components.TestBase; | |||
import com.vaadin.ui.Alignment; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.tests.components.AbstractTestUIWithLog; | |||
import com.vaadin.ui.Button; | |||
import com.vaadin.ui.Button.ClickEvent; | |||
import com.vaadin.ui.Button.ClickListener; | |||
import com.vaadin.ui.HorizontalLayout; | |||
import com.vaadin.ui.Table; | |||
import com.vaadin.ui.TextField; | |||
import com.vaadin.ui.Table.ColumnCollapseEvent; | |||
import com.vaadin.ui.Table.ColumnCollapseListener; | |||
public class ColumnCollapsingAndColumnExpansion extends TestBase { | |||
public class ColumnCollapsingAndColumnExpansion extends AbstractTestUIWithLog { | |||
private Table table; | |||
@Override | |||
public void setup() { | |||
protected void setup(VaadinRequest request) { | |||
table = new Table(); | |||
@@ -50,41 +51,44 @@ public class ColumnCollapsingAndColumnExpansion extends TestBase { | |||
"cell " + 2 + "-" + y, "cell " + 3 + "-" + y, }, | |||
new Object()); | |||
} | |||
addComponent(table); | |||
HorizontalLayout hl = new HorizontalLayout(); | |||
final TextField tf = new TextField("Column name (ColX)"); | |||
Button hide = new Button("Collapse", new ClickListener() { | |||
table.addColumnCollapseListener(new ColumnCollapseListener() { | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
table.setColumnCollapsed(tf.getValue(), true); | |||
} | |||
}); | |||
public void columnCollapseStateChange(ColumnCollapseEvent event) { | |||
log("Collapse state for " + event.getPropertyId() | |||
+ " changed to " | |||
+ table.isColumnCollapsed(event.getPropertyId())); | |||
Button show = new Button("Show", new ClickListener() { | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
table.setColumnCollapsed(tf.getValue(), false); | |||
} | |||
}); | |||
addComponent(table); | |||
hl.addComponent(tf); | |||
hl.addComponent(hide); | |||
hl.addComponent(show); | |||
hl.setComponentAlignment(tf, Alignment.BOTTOM_LEFT); | |||
hl.setComponentAlignment(hide, Alignment.BOTTOM_LEFT); | |||
hl.setComponentAlignment(show, Alignment.BOTTOM_LEFT); | |||
addComponent(hl); | |||
for (int i = 1; i <= 3; i++) { | |||
HorizontalLayout hl = new HorizontalLayout(); | |||
final String id = "Col" + i; | |||
Button hide = new Button("Collapse " + id, new ClickListener() { | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
table.setColumnCollapsed(id, true); | |||
} | |||
}); | |||
Button show = new Button("Show " + id, new ClickListener() { | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
table.setColumnCollapsed(id, false); | |||
} | |||
}); | |||
hl.addComponent(hide); | |||
hl.addComponent(show); | |||
addComponent(hl); | |||
} | |||
} | |||
@Override | |||
protected String getDescription() { | |||
protected String getTestDescription() { | |||
return "After hiding column 2 the remaining columns (1 and 3) should use all available space in the table"; | |||
} | |||
@@ -0,0 +1,112 @@ | |||
/* | |||
* Copyright 2000-2014 Vaadin Ltd. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||
* use this file except in compliance with the License. You may obtain a copy of | |||
* the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||
* License for the specific language governing permissions and limitations under | |||
* the License. | |||
*/ | |||
package com.vaadin.tests.components.table; | |||
import java.io.IOException; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
import org.openqa.selenium.JavascriptExecutor; | |||
import org.openqa.selenium.WebElement; | |||
import com.vaadin.testbench.TestBenchElement; | |||
import com.vaadin.testbench.elements.ButtonElement; | |||
import com.vaadin.testbench.parallel.BrowserUtil; | |||
import com.vaadin.tests.components.table.CustomTableElement.ContextMenuElement; | |||
import com.vaadin.tests.tb3.MultiBrowserTest; | |||
public class ColumnCollapsingAndColumnExpansionTest extends MultiBrowserTest { | |||
@Test | |||
public void expandCorrectlyAfterCollapse() throws IOException { | |||
openTestURL(); | |||
CustomTableElement table = $(CustomTableElement.class).first(); | |||
// Hide col2 through UI | |||
table.openCollapseMenu().getItem(1).click(); | |||
compareScreen(table, "col1-col3"); | |||
// Hide col1 using button | |||
ButtonElement hide1 = $(ButtonElement.class).caption("Collapse Col1") | |||
.first(); | |||
hide1.click(); | |||
compareScreen(table, "col3"); | |||
// Show column 2 using context menu (first action) | |||
if (BrowserUtil.isIE8(getDesiredCapabilities())) { | |||
// IE8 can context click but the popup is off screen so it can't be | |||
// interacted with... | |||
ButtonElement show2 = $(ButtonElement.class).caption("Show Col2") | |||
.first(); | |||
show2.click(); | |||
} else { | |||
contextClick(table.getCell(0, 0)); | |||
ContextMenuElement contextMenu = table.getContextMenu(); | |||
WebElement i = contextMenu.getItem(0); | |||
i.click(); | |||
} | |||
compareScreen(table, "col2-col3"); | |||
// Show column 1 again | |||
ButtonElement show1 = $(ButtonElement.class).caption("Show Col1") | |||
.first(); | |||
show1.click(); | |||
compareScreen(table, "col1-col2-col3"); | |||
} | |||
private void contextClick(TestBenchElement e) { | |||
if (e.isPhantomJS()) { | |||
JavascriptExecutor js = e.getCommandExecutor(); | |||
String scr = "var element=arguments[0];" | |||
+ "var ev = document.createEvent('HTMLEvents');" | |||
+ "ev.initEvent('contextmenu', true, false);" | |||
+ "element.dispatchEvent(ev);"; | |||
js.executeScript(scr, e); | |||
} else { | |||
e.contextClick(); | |||
} | |||
} | |||
@Test | |||
public void collapseEvents() { | |||
openTestURL(); | |||
CustomTableElement table = $(CustomTableElement.class).first(); | |||
// Through menu | |||
table.openCollapseMenu().getItem(0).click(); | |||
Assert.assertEquals("1. Collapse state for Col1 changed to true", | |||
getLogRow(0)); | |||
// Through button | |||
$(ButtonElement.class).caption("Collapse Col2").first().click(); | |||
Assert.assertEquals("2. Collapse state for Col2 changed to true", | |||
getLogRow(0)); | |||
// Show through menu | |||
table.openCollapseMenu().getItem(1).click(); | |||
Assert.assertEquals("3. Collapse state for Col1 changed to false", | |||
getLogRow(0)); | |||
// Show through button | |||
$(ButtonElement.class).caption("Show Col2").first().click(); | |||
Assert.assertEquals("4. Collapse state for Col2 changed to false", | |||
getLogRow(0)); | |||
} | |||
} |
@@ -0,0 +1,57 @@ | |||
/* | |||
* Copyright 2000-2014 Vaadin Ltd. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||
* use this file except in compliance with the License. You may obtain a copy of | |||
* the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||
* License for the specific language governing permissions and limitations under | |||
* the License. | |||
*/ | |||
package com.vaadin.tests.components.table; | |||
import org.openqa.selenium.By; | |||
import org.openqa.selenium.WebElement; | |||
import com.vaadin.testbench.elements.TableElement; | |||
import com.vaadin.testbench.elementsbase.AbstractElement; | |||
import com.vaadin.testbench.elementsbase.ServerClass; | |||
@ServerClass("com.vaadin.ui.Table") | |||
public class CustomTableElement extends TableElement { | |||
public CollapseMenu openCollapseMenu() { | |||
getCollapseMenuToggle().click(); | |||
WebElement cm = getDriver().findElement( | |||
By.xpath("//*[@id='PID_VAADIN_CM']")); | |||
return wrapElement(cm, getCommandExecutor()).wrap(CollapseMenu.class); | |||
} | |||
public static class CollapseMenu extends ContextMenuElement { | |||
} | |||
public WebElement getCollapseMenuToggle() { | |||
return findElement(By.className("v-table-column-selector")); | |||
} | |||
public static class ContextMenuElement extends AbstractElement { | |||
public WebElement getItem(int index) { | |||
return findElement(By.xpath(".//table//tr[" + (index + 1) | |||
+ "]//td/*")); | |||
} | |||
} | |||
public ContextMenuElement getContextMenu() { | |||
WebElement cm = getDriver().findElement(By.className("v-contextmenu")); | |||
return wrapElement(cm, getCommandExecutor()).wrap( | |||
ContextMenuElement.class); | |||
} | |||
} |
@@ -1,97 +0,0 @@ | |||
<?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>ColumnCollapsingAndColumnExpansion</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr><td rowspan="1" colspan="3">ColumnCollapsingAndColumnExpansion</td></tr> | |||
</thead><tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/run/com.vaadin.tests.components.table.ColumnCollapsingAndColumnExpansion?restartApplication</td> | |||
<td></td> | |||
</tr> | |||
<!--Initial state, all 3 columns visible--> | |||
<tr> | |||
<td>screenCapture</td> | |||
<td></td> | |||
<td>col1-col2-col3-visible</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[0]/domChild[1]</td> | |||
<td></td> | |||
</tr> | |||
<!--Hide 'col2' through table interface--> | |||
<tr> | |||
<td>mouseClick</td> | |||
<td>//tr[2]/td/span/div</td> | |||
<td>23,2</td> | |||
</tr> | |||
<tr> | |||
<td>screenCapture</td> | |||
<td></td> | |||
<td>col2-hidden</td> | |||
</tr> | |||
<!--Hide 'Col1' using button--> | |||
<tr> | |||
<td>enterCharacter</td> | |||
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VTextField[0]</td> | |||
<td>Col1</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>screenCapture</td> | |||
<td></td> | |||
<td>col1-col2-hidden</td> | |||
</tr> | |||
<!--Show 'col2' using action handler--> | |||
<tr> | |||
<td>contextmenu</td> | |||
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>mouseClick</td> | |||
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VContextMenu[0]#option0</td> | |||
<td>11,6</td> | |||
</tr> | |||
<tr> | |||
<td>enterCharacter</td> | |||
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VTextField[0]</td> | |||
<td>Col2</td> | |||
</tr> | |||
<tr> | |||
<td>screenCapture</td> | |||
<td></td> | |||
<td>col1-hidden</td> | |||
</tr> | |||
<!--Show 'Col1' using button--> | |||
<tr> | |||
<td>enterCharacter</td> | |||
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VTextField[0]</td> | |||
<td>Col1</td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> | |||
<td></td> | |||
</tr> | |||
<!--We should now be back at the initial state, all 3 columns visible--> | |||
<tr> | |||
<td>screenCapture</td> | |||
<td></td> | |||
<td>col1-col2-col3-visible-again</td> | |||
</tr> | |||
</tbody></table> | |||
</body> | |||
</html> |