Change-Id: Id4f119b22d44f6abf63e730442e22a34e7c1953ftags/7.6.0.alpha2
import com.vaadin.shared.EventId; | import com.vaadin.shared.EventId; | ||||
import com.vaadin.shared.ui.ComponentStateUtil; | import com.vaadin.shared.ui.ComponentStateUtil; | ||||
import com.vaadin.shared.ui.combobox.FilteringMode; | import com.vaadin.shared.ui.combobox.FilteringMode; | ||||
import com.vaadin.shared.util.SharedUtil; | |||||
/** | /** | ||||
* Client side implementation of the Select component. | * Client side implementation of the Select component. | ||||
private final String key; | private final String key; | ||||
private final String caption; | private final String caption; | ||||
private String iconUri; | |||||
private String untranslatedIconUri; | |||||
/** | /** | ||||
* Constructor | * Constructor | ||||
key = uidl.getStringAttribute("key"); | key = uidl.getStringAttribute("key"); | ||||
caption = uidl.getStringAttribute("caption"); | caption = uidl.getStringAttribute("caption"); | ||||
if (uidl.hasAttribute("icon")) { | if (uidl.hasAttribute("icon")) { | ||||
iconUri = client.translateVaadinUri(uidl | |||||
.getStringAttribute("icon")); | |||||
untranslatedIconUri = uidl.getStringAttribute("icon"); | |||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public String getDisplayString() { | public String getDisplayString() { | ||||
final StringBuffer sb = new StringBuffer(); | final StringBuffer sb = new StringBuffer(); | ||||
final Icon icon = client.getIcon(iconUri); | |||||
final Icon icon = client.getIcon(client | |||||
.translateVaadinUri(untranslatedIconUri)); | |||||
if (icon != null) { | if (icon != null) { | ||||
sb.append(icon.getElement().getString()); | sb.append(icon.getElement().getString()); | ||||
} | } | ||||
* @return | * @return | ||||
*/ | */ | ||||
public String getIconUri() { | public String getIconUri() { | ||||
return iconUri; | |||||
return client.translateVaadinUri(untranslatedIconUri); | |||||
} | } | ||||
/** | /** | ||||
|| (caption != null && !caption.equals(other.caption))) { | || (caption != null && !caption.equals(other.caption))) { | ||||
return false; | return false; | ||||
} | } | ||||
if ((iconUri == null && other.iconUri != null) | |||||
|| (iconUri != null && !iconUri.equals(other.iconUri))) { | |||||
if (!SharedUtil.equals(untranslatedIconUri, | |||||
other.untranslatedIconUri)) { | |||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; |
actionMap.put(key + "_c", caption); | actionMap.put(key + "_c", caption); | ||||
if (action.hasAttribute("icon")) { | if (action.hasAttribute("icon")) { | ||||
// TODO need some uri handling ?? | // TODO need some uri handling ?? | ||||
actionMap.put(key + "_i", client.translateVaadinUri(action | |||||
.getStringAttribute("icon"))); | |||||
actionMap.put(key + "_i", action.getStringAttribute("icon")); | |||||
} else { | } else { | ||||
actionMap.remove(key + "_i"); | actionMap.remove(key + "_i"); | ||||
} | } | ||||
} | } | ||||
public String getActionIcon(String actionKey) { | public String getActionIcon(String actionKey) { | ||||
return actionMap.get(actionKey + "_i"); | |||||
return client.translateVaadinUri(actionMap.get(actionKey + "_i")); | |||||
} | } | ||||
private void updateHeader(String[] strings) { | private void updateHeader(String[] strings) { |
activeTheme); | activeTheme); | ||||
} | } | ||||
String oldThemeBase = getConnection().translateVaadinUri("theme://"); | |||||
activeTheme = newTheme; | activeTheme = newTheme; | ||||
if (newTheme != null) { | if (newTheme != null) { | ||||
activeTheme); | activeTheme); | ||||
updateVaadinFavicon(newTheme); | updateVaadinFavicon(newTheme); | ||||
} | } | ||||
forceStateChangeRecursively(UIConnector.this); | forceStateChangeRecursively(UIConnector.this); | ||||
// UIDL has no stored URL which we can repaint so we do some find and | |||||
// replace magic... | |||||
String newThemeBase = getConnection().translateVaadinUri("theme://"); | |||||
replaceThemeAttribute(oldThemeBase, newThemeBase); | |||||
getLayoutManager().forceLayout(); | getLayoutManager().forceLayout(); | ||||
} | } | ||||
/** | |||||
* Finds all attributes where theme:// urls have possibly been used and | |||||
* replaces any old theme url with a new one | |||||
* | |||||
* @param oldPrefix | |||||
* The start of the old theme URL | |||||
* @param newPrefix | |||||
* The start of the new theme URL | |||||
*/ | |||||
private void replaceThemeAttribute(String oldPrefix, String newPrefix) { | |||||
// Images | |||||
replaceThemeAttribute("src", oldPrefix, newPrefix); | |||||
// Embedded flash | |||||
replaceThemeAttribute("value", oldPrefix, newPrefix); | |||||
replaceThemeAttribute("movie", oldPrefix, newPrefix); | |||||
} | |||||
/** | |||||
* Finds any attribute of the given type where theme:// urls have possibly | |||||
* been used and replaces any old theme url with a new one | |||||
* | |||||
* @param attributeName | |||||
* The name of the attribute, e.g. "src" | |||||
* @param oldPrefix | |||||
* The start of the old theme URL | |||||
* @param newPrefix | |||||
* The start of the new theme URL | |||||
*/ | |||||
private void replaceThemeAttribute(String attributeName, String oldPrefix, | |||||
String newPrefix) { | |||||
// Find all "attributeName=" which start with "oldPrefix" using e.g. | |||||
// [^src='http://oldpath'] | |||||
NodeList<Element> elements = querySelectorAll("[" + attributeName | |||||
+ "^='" + oldPrefix + "']"); | |||||
for (int i = 0; i < elements.getLength(); i++) { | |||||
Element element = elements.getItem(i); | |||||
element.setAttribute( | |||||
attributeName, | |||||
element.getAttribute(attributeName).replace(oldPrefix, | |||||
newPrefix)); | |||||
} | |||||
} | |||||
/** | /** | ||||
* Force a full recursive recheck of every connector's state variables. | * Force a full recursive recheck of every connector's state variables. | ||||
* | * |
/* | |||||
* Copyright 2000-2013 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.themes; | |||||
import com.vaadin.annotations.Theme; | |||||
import com.vaadin.event.Action; | |||||
import com.vaadin.event.Action.Handler; | |||||
import com.vaadin.server.ThemeResource; | |||||
import com.vaadin.server.VaadinRequest; | |||||
import com.vaadin.tests.components.AbstractTestUIWithLog; | |||||
import com.vaadin.tests.util.PersonContainer; | |||||
import com.vaadin.ui.Button; | |||||
import com.vaadin.ui.Button.ClickEvent; | |||||
import com.vaadin.ui.Button.ClickListener; | |||||
import com.vaadin.ui.ComboBox; | |||||
import com.vaadin.ui.Embedded; | |||||
import com.vaadin.ui.HorizontalLayout; | |||||
import com.vaadin.ui.MenuBar; | |||||
import com.vaadin.ui.Table; | |||||
import com.vaadin.ui.VerticalLayout; | |||||
@Theme("reindeer") | |||||
public class LegacyComponentThemeChange extends AbstractTestUIWithLog { | |||||
@Override | |||||
protected void setup(VaadinRequest request) { | |||||
VerticalLayout vl = new VerticalLayout(); | |||||
vl.setCaption("Change theme by clicking a button"); | |||||
HorizontalLayout hl = new HorizontalLayout(); | |||||
for (final String theme : new String[] { "reindeer", "runo" }) { | |||||
Button b = new Button(theme); | |||||
b.setId(theme + ""); | |||||
b.addClickListener(new ClickListener() { | |||||
@Override | |||||
public void buttonClick(ClickEvent event) { | |||||
getUI().setTheme(theme); | |||||
} | |||||
}); | |||||
hl.addComponent(b); | |||||
} | |||||
vl.addComponent(hl); | |||||
// Always wants to use icon from Runo, even if we change theme | |||||
ThemeResource alwaysTheSameIconImage = new ThemeResource( | |||||
"../runo/icons/16/ok.png"); | |||||
ThemeResource varyingIcon = new ThemeResource("menubar-theme-icon.png"); | |||||
MenuBar bar = new MenuBar(); | |||||
bar.addItem("runo", alwaysTheSameIconImage, null); | |||||
bar.addItem("seletedtheme", varyingIcon, null); | |||||
vl.addComponent(bar); | |||||
ComboBox cb = new ComboBox("ComboBox"); | |||||
cb.addItem("No icon"); | |||||
cb.addItem("Icon"); | |||||
cb.setItemIcon("Icon", new ThemeResource("comboboxicon.png")); | |||||
cb.setValue("Icon"); | |||||
vl.addComponent(cb); | |||||
Embedded e = new Embedded("embedded"); | |||||
e.setMimeType("application/x-shockwave-flash"); | |||||
e.setType(Embedded.TYPE_OBJECT); | |||||
e.setSource(new ThemeResource("embedded.src")); | |||||
vl.addComponent(e); | |||||
Table t = new Table(); | |||||
t.addActionHandler(new Handler() { | |||||
@Override | |||||
public void handleAction(Action action, Object sender, Object target) { | |||||
} | |||||
@Override | |||||
public Action[] getActions(Object target, Object sender) { | |||||
return new Action[] { new Action("Theme icon", | |||||
new ThemeResource("action-icon.png")) }; | |||||
} | |||||
}); | |||||
PersonContainer pc = PersonContainer.createWithTestData(); | |||||
pc.addNestedContainerBean("address"); | |||||
t.setContainerDataSource(pc); | |||||
vl.addComponent(t); | |||||
addComponent(vl); | |||||
} | |||||
} |
/* | |||||
* Copyright 2000-2013 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.themes; | |||||
import java.util.List; | |||||
import org.junit.Assert; | |||||
import org.junit.Test; | |||||
import org.openqa.selenium.By; | |||||
import org.openqa.selenium.WebDriver; | |||||
import org.openqa.selenium.WebElement; | |||||
import org.openqa.selenium.remote.DesiredCapabilities; | |||||
import org.openqa.selenium.support.ui.ExpectedCondition; | |||||
import com.vaadin.testbench.elements.ButtonElement; | |||||
import com.vaadin.testbench.elements.ComboBoxElement; | |||||
import com.vaadin.testbench.elements.EmbeddedElement; | |||||
import com.vaadin.testbench.elements.MenuBarElement; | |||||
import com.vaadin.testbench.elements.TableElement; | |||||
import com.vaadin.testbench.parallel.Browser; | |||||
import com.vaadin.testbench.parallel.BrowserUtil; | |||||
import com.vaadin.tests.tb3.MultiBrowserTest; | |||||
public class LegacyComponentThemeChangeTest extends MultiBrowserTest { | |||||
@Override | |||||
public List<DesiredCapabilities> getBrowsersToTest() { | |||||
// Seems like stylesheet onload is not fired on PhantomJS | |||||
// https://github.com/ariya/phantomjs/issues/12332 | |||||
List<DesiredCapabilities> l = getBrowsersExcludingPhantomJS(); | |||||
// For some reason, IE times out when trying to open the combobox, | |||||
// #18341 | |||||
l.remove(Browser.IE11.getDesiredCapabilities()); | |||||
return l; | |||||
} | |||||
@Test | |||||
public void legacyComponentThemeResourceChange() { | |||||
openTestURL(); | |||||
String theme = "reindeer"; | |||||
assertMenubarTheme(theme); | |||||
assertCombobBoxTheme(theme); | |||||
assertTableTheme(theme); | |||||
assertEmbeddedTheme(theme); | |||||
theme = "runo"; | |||||
changeTheme(theme); | |||||
assertMenubarTheme(theme); | |||||
assertCombobBoxTheme(theme); | |||||
assertTableTheme(theme); | |||||
assertEmbeddedTheme(theme); | |||||
theme = "reindeer"; | |||||
changeTheme(theme); | |||||
assertMenubarTheme(theme); | |||||
assertCombobBoxTheme(theme); | |||||
assertTableTheme(theme); | |||||
assertEmbeddedTheme(theme); | |||||
} | |||||
private void assertEmbeddedTheme(String theme) { | |||||
if (BrowserUtil.isIE8(getDesiredCapabilities())) { | |||||
// IE8 won't initialize the dummy flash properly | |||||
return; | |||||
} | |||||
EmbeddedElement e = $(EmbeddedElement.class).first(); | |||||
WebElement movieParam = e.findElement(By | |||||
.xpath(".//param[@name='movie']")); | |||||
WebElement embed = e.findElement(By.xpath(".//embed")); | |||||
assertAttributePrefix(movieParam, "value", theme); | |||||
assertAttributePrefix(embed, "src", theme); | |||||
assertAttributePrefix(embed, "movie", theme); | |||||
} | |||||
private void assertTableTheme(String theme) { | |||||
TableElement t = $(TableElement.class).first(); | |||||
t.getRow(0).contextClick(); | |||||
WebElement popup = findElement(By.className("v-contextmenu")); | |||||
WebElement actionImage = popup.findElement(By.xpath(".//img")); | |||||
assertAttributePrefix(actionImage, "src", theme); | |||||
} | |||||
private void assertCombobBoxTheme(String theme) { | |||||
ComboBoxElement cb = $(ComboBoxElement.class).first(); | |||||
WebElement selectedImage = cb.findElement(By.xpath("./img")); | |||||
assertAttributePrefix(selectedImage, "src", theme); | |||||
cb.openPopup(); | |||||
WebElement popup = findElement(By | |||||
.className("v-filterselect-suggestpopup")); | |||||
WebElement itemImage = popup.findElement(By.xpath(".//img")); | |||||
assertAttributePrefix(itemImage, "src", theme); | |||||
} | |||||
private void assertMenubarTheme(String theme) { | |||||
// The runoImage must always come from Runo | |||||
WebElement runoImage = $(MenuBarElement.class).first().findElement( | |||||
By.xpath(".//span[text()='runo']/img")); | |||||
String runoImageSrc = runoImage.getAttribute("src"); | |||||
// Something in Selenium normalizes the image so it becomes | |||||
// "/themes/runo/icons/16/ok.png" here although it is | |||||
// "/themes/<currenttheme>/../runo/icons/16/ok.png" in the browser | |||||
Assert.assertEquals(getThemeURL("runo") + "icons/16/ok.png", | |||||
runoImageSrc); | |||||
// The other image should change with the theme | |||||
WebElement themeImage = $(MenuBarElement.class).first().findElement( | |||||
By.xpath(".//span[text()='seletedtheme']/img")); | |||||
assertAttributePrefix(themeImage, "src", theme); | |||||
} | |||||
private void assertAttributePrefix(WebElement element, String attribute, | |||||
String theme) { | |||||
String value = element.getAttribute(attribute); | |||||
String expectedPrefix = getThemeURL(theme); | |||||
Assert.assertTrue("Attribute " + attribute + "='" + value | |||||
+ "' does not start with " + expectedPrefix, | |||||
value.startsWith(expectedPrefix)); | |||||
} | |||||
private String getThemeURL(String theme) { | |||||
return getBaseURL() + "/VAADIN/themes/" + theme + "/"; | |||||
} | |||||
private void changeTheme(String theme) { | |||||
$(ButtonElement.class).id(theme).click(); | |||||
waitForThemeToChange(theme); | |||||
} | |||||
private void waitForThemeToChange(final String theme) { | |||||
final WebElement rootDiv = findElement(By | |||||
.xpath("//div[contains(@class,'v-app')]")); | |||||
waitUntil(new ExpectedCondition<Boolean>() { | |||||
@Override | |||||
public Boolean apply(WebDriver input) { | |||||
String rootClass = rootDiv.getAttribute("class").trim(); | |||||
return rootClass.contains(theme); | |||||
} | |||||
}, 30); | |||||
} | |||||
} |