diff options
author | Jouni Koivuviita <jouni.koivuviita@itmill.com> | 2009-08-27 12:26:49 +0000 |
---|---|---|
committer | Jouni Koivuviita <jouni.koivuviita@itmill.com> | 2009-08-27 12:26:49 +0000 |
commit | ad101f842727ca84a184f1bf1ad7c5e63878302b (patch) | |
tree | b636516fa19ef5dab996c9160e576e3169e50f7b /src | |
parent | 7072fbb2f053ab9a390ee5e004d65e465c7b93e7 (diff) | |
download | vaadin-framework-ad101f842727ca84a184f1bf1ad7c5e63878302b.tar.gz vaadin-framework-ad101f842727ca84a184f1bf1ad7c5e63878302b.zip |
The Button Component Strikes Back
Fixes many theme issues with Button (mostly Reindeer theme), including #3110, #3193, #3194, #3180 and 3079.
Default button is now rendered on the client side with a DIV. Disabled buttons can now have descriptions, which fixes #2085.
Added a "new" component, NativeButton, which uses native BUTTON element rendering on the client side.
Theme compilation script now understands simple @import statements, which help keep things more organized in theme development.
svn changeset:8558/svn branch:6.1
Diffstat (limited to 'src')
-rw-r--r-- | src/com/vaadin/demo/sampler/ModeSwitch.java | 3 | ||||
-rw-r--r-- | src/com/vaadin/demo/sampler/SamplerApplication.java | 11 | ||||
-rwxr-xr-x | src/com/vaadin/terminal/gwt/client/ApplicationConnection.java | 3 | ||||
-rw-r--r-- | src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java | 7 | ||||
-rw-r--r-- | src/com/vaadin/terminal/gwt/client/ui/VButton.java | 429 | ||||
-rw-r--r-- | src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java | 5 | ||||
-rw-r--r-- | src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java | 182 | ||||
-rw-r--r-- | src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java | 4 | ||||
-rw-r--r-- | src/com/vaadin/tests/themes/ButtonsTest.java | 158 | ||||
-rw-r--r-- | src/com/vaadin/tests/themes/ReindeerButtonsTest.java | 82 | ||||
-rw-r--r-- | src/com/vaadin/ui/Button.java | 34 | ||||
-rw-r--r-- | src/com/vaadin/ui/NativeButton.java | 51 |
12 files changed, 739 insertions, 230 deletions
diff --git a/src/com/vaadin/demo/sampler/ModeSwitch.java b/src/com/vaadin/demo/sampler/ModeSwitch.java index 738f9f07cb..62a1ab8ef4 100644 --- a/src/com/vaadin/demo/sampler/ModeSwitch.java +++ b/src/com/vaadin/demo/sampler/ModeSwitch.java @@ -7,6 +7,7 @@ import com.vaadin.terminal.Resource; import com.vaadin.ui.Button; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.GridLayout; +import com.vaadin.ui.NativeButton; import com.vaadin.ui.Button.ClickEvent; @SuppressWarnings("serial") @@ -45,7 +46,7 @@ public class ModeSwitch extends CustomComponent { if (idToButton.containsKey(id)) { removeMode(id); } - Button b = new Button(); + Button b = new NativeButton(); if (caption != null) { b.setCaption(caption); } diff --git a/src/com/vaadin/demo/sampler/SamplerApplication.java b/src/com/vaadin/demo/sampler/SamplerApplication.java index 2b5fc4a8ac..85978c16da 100644 --- a/src/com/vaadin/demo/sampler/SamplerApplication.java +++ b/src/com/vaadin/demo/sampler/SamplerApplication.java @@ -30,6 +30,7 @@ import com.vaadin.ui.Embedded; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.NativeButton; import com.vaadin.ui.Panel; import com.vaadin.ui.PopupView; import com.vaadin.ui.SplitPanel; @@ -358,7 +359,7 @@ public class SamplerApplication extends Application { } private Component createLogo() { - Button logo = new Button("", new Button.ClickListener() { + Button logo = new NativeButton("", new Button.ClickListener() { public void buttonClick(ClickEvent event) { setFeature((Feature) null); } @@ -371,7 +372,7 @@ public class SamplerApplication extends Application { } private Button createNextButton() { - Button b = new Button("", new ClickListener() { + Button b = new NativeButton("", new ClickListener() { public void buttonClick(ClickEvent event) { Object curr = currentFeature.getValue(); Object next = allFeatures.nextItemId(curr); @@ -392,7 +393,7 @@ public class SamplerApplication extends Application { } private Button createPrevButton() { - Button b = new Button("", new ClickListener() { + Button b = new NativeButton("", new ClickListener() { public void buttonClick(ClickEvent event) { Object curr = currentFeature.getValue(); Object prev = allFeatures.prevItemId(curr); @@ -409,7 +410,7 @@ public class SamplerApplication extends Application { } private Component createTreeSwitch() { - final Button b = new Button(); + final Button b = new NativeButton(); b.setStyleName("tree-switch"); b.setDescription("Toggle sample tree visibility"); b.addListener(new Button.ClickListener() { @@ -716,7 +717,7 @@ public class SamplerApplication extends Application { if (grid.getCursorX() == 0) { grid.space(); } - Button b = new Button(); + Button b = new NativeButton(); b.setStyleName(Button.STYLE_LINK); b.addStyleName("screenshot"); String resId = "75-" + f.getIconName(); diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index a6965b2693..69174587a6 100755 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -1108,10 +1108,11 @@ public class ApplicationConnection { boolean enabled = !uidl.getBooleanAttribute("disabled"); if (component instanceof FocusWidget) { FocusWidget fw = (FocusWidget) component; - fw.setEnabled(enabled); if (uidl.hasAttribute("tabindex")) { fw.setTabIndex(uidl.getIntAttribute("tabindex")); } + // Disabled state may affect tabindex + fw.setEnabled(enabled); } StringBuffer styleBuf = new StringBuffer(); diff --git a/src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java b/src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java index 9ac2337004..f72859dbfb 100644 --- a/src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java +++ b/src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java @@ -22,6 +22,7 @@ import com.vaadin.terminal.gwt.client.ui.VLabel; import com.vaadin.terminal.gwt.client.ui.VLink; import com.vaadin.terminal.gwt.client.ui.VListSelect; import com.vaadin.terminal.gwt.client.ui.VMenuBar; +import com.vaadin.terminal.gwt.client.ui.VNativeButton; import com.vaadin.terminal.gwt.client.ui.VNativeSelect; import com.vaadin.terminal.gwt.client.ui.VOptionGroup; import com.vaadin.terminal.gwt.client.ui.VOrderedLayout; @@ -64,6 +65,8 @@ public class DefaultWidgetSet implements WidgetSet { return new VCheckBox(); } else if (VButton.class == classType) { return new VButton(); + } else if (VNativeButton.class == classType) { + return new VNativeButton(); } else if (VWindow.class == classType) { return new VWindow(); } else if (VOrderedLayout.class == classType) { @@ -150,9 +153,11 @@ public class DefaultWidgetSet implements WidgetSet { protected Class resolveWidgetType(UIDL uidl) { final String tag = uidl.getTag(); - if ("button".equals(tag)) { + if ("button".equals(tag) || "nativebutton".equals(tag)) { if ("switch".equals(uidl.getStringAttribute("type"))) { return VCheckBox.class; + } else if ("nativebutton".equals(tag)) { + return VNativeButton.class; } else { return VButton.class; } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VButton.java b/src/com/vaadin/terminal/gwt/client/ui/VButton.java index 768b98727b..b3213b1b8f 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VButton.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VButton.java @@ -4,14 +4,15 @@ package com.vaadin.terminal.gwt.client.ui; -import com.google.gwt.user.client.Command; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.DeferredCommand; -import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.ui.Button; -import com.google.gwt.user.client.ui.ClickListener; -import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.user.client.ui.Accessibility; +import com.google.gwt.user.client.ui.FocusWidget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.Paintable; @@ -19,70 +20,86 @@ import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VTooltip; -public class VButton extends Button implements Paintable { - - private String width = null; +public class VButton extends FocusWidget implements Paintable { public static final String CLASSNAME = "v-button"; + private static final String CLASSNAME_PRESSED = "v-pressed"; - // Used only for IE, because it doesn't support :active CSS selector - private static final String CLASSNAME_DOWN = "v-pressed"; - - private String primaryStyleName; + protected String id; - String id; + protected ApplicationConnection client; - ApplicationConnection client; + protected final Element wrapper = DOM.createSpan(); - private Element errorIndicatorElement; + protected Element errorIndicatorElement; - private final Element captionElement = DOM.createSpan(); + protected final Element captionElement = DOM.createSpan(); - private Icon icon; + protected Icon icon; /** - * Helper flat to handle special-case where the button is moved from under + * Helper flag to handle special-case where the button is moved from under * mouse while clicking it. In this case mouse leaves the button without * moving. */ private boolean clickPending; + /* + * BELOW PRIVATE MEMBERS COPY-PASTED FROM GWT CustomButton + */ + + /** + * If <code>true</code>, this widget is capturing with the mouse held down. + */ + private boolean isCapturing; + + /** + * If <code>true</code>, this widget has focus with the space bar down. + */ + private boolean isFocusing; + + /** + * Used to decide whether to allow clicks to propagate up to the superclass + * or container elements. + */ + private boolean allowClick; + private boolean isHovering; + private boolean enabled = true; + private int tabIndex = 0; + public VButton() { + super(DOM.createDiv()); + setTabIndex(0); + sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.FOCUSEVENTS + | Event.KEYEVENTS); + sinkEvents(VTooltip.TOOLTIP_EVENTS); + setStyleName(CLASSNAME); - DOM.appendChild(getElement(), captionElement); - captionElement.setPropertyString("className", CLASSNAME + "-caption"); + // Add a11y role "button" + Accessibility.setRole(getElement(), Accessibility.ROLE_BUTTON); - addClickListener(new ClickListener() { - public void onClick(Widget sender) { + wrapper.setClassName(CLASSNAME + "-wrap"); + getElement().appendChild(wrapper); + captionElement.setClassName(CLASSNAME + "-caption"); + wrapper.appendChild(captionElement); + + addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { if (id == null || client == null) { return; } - /* - * TODO isolate workaround. Safari don't always seem to fire - * onblur previously focused component before button is clicked. - */ - VButton.this.setFocus(true); + if (BrowserInfo.get().isSafari()) { + VButton.this.setFocus(true); + } client.updateVariable(id, "state", true, true); clickPending = false; } }); - sinkEvents(VTooltip.TOOLTIP_EVENTS); - sinkEvents(Event.ONMOUSEDOWN); - sinkEvents(Event.ONMOUSEUP); } public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - // client.updateComponent depends on this, so this must come before - if (uidl.hasAttribute("primarystyle") - && primaryStyleName != uidl.getStringAttribute("primarystyle")) { - primaryStyleName = uidl.getStringAttribute("primarystyle"); - setStyleName(primaryStyleName); - captionElement.setPropertyString("className", getStylePrimaryName() - + "-caption"); - } - // Ensure correct implementation, // but don't let container manage caption etc. if (client.updateComponent(this, uidl, false)) { @@ -100,115 +117,321 @@ public class VButton extends Button implements Paintable { if (uidl.hasAttribute("error")) { if (errorIndicatorElement == null) { errorIndicatorElement = DOM.createSpan(); - DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); + errorIndicatorElement.setClassName("v-errorindicator"); } - DOM.insertChild(getElement(), errorIndicatorElement, 0); + wrapper.insertBefore(errorIndicatorElement, captionElement); // Fix for IE6, IE7 - if (BrowserInfo.get().isIE()) { - DOM.setInnerText(errorIndicatorElement, " "); + if (BrowserInfo.get().isIE6() || BrowserInfo.get().isIE7()) { + errorIndicatorElement.setInnerText(" "); } } else if (errorIndicatorElement != null) { - DOM.removeChild(getElement(), errorIndicatorElement); + wrapper.removeChild(errorIndicatorElement); errorIndicatorElement = null; } - if (uidl.hasAttribute("readonly")) { - setEnabled(false); - } - if (uidl.hasAttribute("icon")) { if (icon == null) { icon = new Icon(client); - DOM.insertChild(getElement(), icon.getElement(), 0); + wrapper.insertBefore(icon.getElement(), captionElement); } icon.setUri(uidl.getStringAttribute("icon")); } else { if (icon != null) { - DOM.removeChild(getElement(), icon.getElement()); + wrapper.removeChild(icon.getElement()); icon = null; } } - if (BrowserInfo.get().isIE7()) { - /* - * Workaround for IE7 size calculation issues. Deferred because of - * issues with a button with an icon using the reindeer theme - */ - if (width.equals("")) { - DeferredCommand.addCommand(new Command() { - - public void execute() { - setWidth(""); - setWidth(getOffsetWidth() + "px"); - } - }); - } - } } - @Override public void setText(String text) { - DOM.setInnerText(captionElement, text); + captionElement.setInnerText(text); } + @SuppressWarnings("deprecation") @Override + /* + * Copy-pasted from GWT CustomButton, some minor modifications done: + * + * -for IE/Opera added CLASSNAME_PRESSED + * + * -event.preventDefault() commented from ONMOUSEDOWN (Firefox won't apply + * :active styles if it is present) + * + * -Tooltip event handling added + * + * -onload event handler added (for icon handling) + */ public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - + if (client != null) { + client.handleTooltipEvent(event, this); + } if (DOM.eventGetType(event) == Event.ONLOAD) { Util.notifyParentOfSizeChange(this, true); + } + // Should not act on button if disabled. + if (!isEnabled()) { + // This can happen when events are bubbled up from non-disabled + // children + return; + } - } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN - && event.getButton() == Event.BUTTON_LEFT) { - clickPending = true; - if (BrowserInfo.get().isIE()) { - // Only for IE, because it doesn't support :active CSS selector - // Simple check is cheaper than DOM manipulation - addStyleName(CLASSNAME_DOWN); + int type = DOM.eventGetType(event); + switch (type) { + case Event.ONCLICK: + // If clicks are currently disallowed, keep it from bubbling or + // being passed to the superclass. + if (!allowClick) { + event.stopPropagation(); + return; } - } else if (DOM.eventGetType(event) == Event.ONMOUSEMOVE) { - clickPending = false; - } else if (DOM.eventGetType(event) == Event.ONMOUSEOUT) { - if (clickPending) { - click(); + break; + case Event.ONMOUSEDOWN: + if (event.getButton() == Event.BUTTON_LEFT) { + clickPending = true; + setFocus(true); + DOM.setCapture(getElement()); + isCapturing = true; + // Prevent dragging (on some browsers); + // DOM.eventPreventDefault(event); + if (BrowserInfo.get().isIE() || BrowserInfo.get().isOpera()) { + addStyleName(CLASSNAME_PRESSED); + } } - if (BrowserInfo.get().isIE()) { - removeStyleName(CLASSNAME_DOWN); + break; + case Event.ONMOUSEUP: + if (isCapturing) { + isCapturing = false; + DOM.releaseCapture(getElement()); + if (isHovering() && event.getButton() == Event.BUTTON_LEFT) { + onClick(); + } + if (BrowserInfo.get().isIE() || BrowserInfo.get().isOpera()) { + removeStyleName(CLASSNAME_PRESSED); + } } + break; + case Event.ONMOUSEMOVE: clickPending = false; - } else if (DOM.eventGetType(event) == Event.ONMOUSEUP) { - if (BrowserInfo.get().isIE()) { - removeStyleName(CLASSNAME_DOWN); + if (isCapturing) { + // Prevent dragging (on other browsers); + DOM.eventPreventDefault(event); + } + break; + case Event.ONMOUSEOUT: + Element to = event.getRelatedTarget(); + if (getElement().isOrHasChild(DOM.eventGetTarget(event)) + && (to == null || !getElement().isOrHasChild(to))) { + if (clickPending) { + onClick(); + break; + } + clickPending = false; + if (isCapturing) { + } + setHovering(false); + if (BrowserInfo.get().isIE() || BrowserInfo.get().isOpera()) { + removeStyleName(CLASSNAME_PRESSED); + } + } + break; + case Event.ONMOUSEOVER: + if (DOM.isOrHasChild(getElement(), DOM.eventGetTarget(event))) { + setHovering(true); + if (isCapturing) { + } + } + break; + case Event.ONBLUR: + if (isFocusing) { + isFocusing = false; } + break; + case Event.ONLOSECAPTURE: + if (isCapturing) { + isCapturing = false; + } + break; } - if (client != null) { - client.handleTooltipEvent(event, this); + super.onBrowserEvent(event); + + // Synthesize clicks based on keyboard events AFTER the normal key + // handling. + if ((event.getTypeInt() & Event.KEYEVENTS) != 0) { + char keyCode = (char) DOM.eventGetKeyCode(event); + switch (type) { + case Event.ONKEYDOWN: + if (keyCode == ' ') { + isFocusing = true; + event.preventDefault(); + } + break; + case Event.ONKEYUP: + if (isFocusing && keyCode == ' ') { + isFocusing = false; + onClick(); + event.preventDefault(); + } + break; + case Event.ONKEYPRESS: + if (keyCode == '\n' || keyCode == '\r') { + onClick(); + event.preventDefault(); + } + break; + } + } + } + + final void setHovering(boolean hovering) { + if (hovering != isHovering()) { + isHovering = hovering; } } + final boolean isHovering() { + return isHovering; + } + + /* + * ALL BELOW COPY-PASTED FROM GWT CustomButton + */ + + /** + * Called when the user finishes clicking on this button. The default + * behavior is to fire the click event to listeners. Subclasses that + * override {@link #onClickStart()} should override this method to restore + * the normal widget display. + */ + protected void onClick() { + // Allow the click we're about to synthesize to pass through to the + // superclass and containing elements. Element.dispatchEvent() is + // synchronous, so we simply set and clear the flag within this method. + allowClick = true; + + // Mouse coordinates are not always available (e.g., when the click is + // caused by a keyboard event). + NativeEvent evt = Document.get().createClickEvent(1, 0, 0, 0, 0, false, + false, false, false); + getElement().dispatchEvent(evt); + + allowClick = false; + } + + /** + * Sets whether this button is enabled. + * + * @param enabled + * <code>true</code> to enable the button, <code>false</code> to + * disable it + */ + @Override - public void setWidth(String width) { - /* Workaround for IE7 button size part 1 (#2014) */ - if (BrowserInfo.get().isIE7() && this.width != null) { - if (this.width.equals(width)) { - return; + public final void setEnabled(boolean enabled) { + if (isEnabled() != enabled) { + this.enabled = enabled; + if (!enabled) { + cleanupCaptureState(); + Accessibility.removeState(getElement(), + Accessibility.STATE_PRESSED); + super.setTabIndex(-1); + } else { + Accessibility.setState(getElement(), + Accessibility.STATE_PRESSED, "false"); + super.setTabIndex(tabIndex); } + } + } - if (width == null) { - width = ""; - } + @Override + public final boolean isEnabled() { + return enabled; + } + + @Override + public final void setTabIndex(int index) { + super.setTabIndex(index); + tabIndex = index; + } + + /** + * Resets internal state if this button can no longer service events. This + * can occur when the widget becomes detached or disabled. + */ + private void cleanupCaptureState() { + if (isCapturing || isFocusing) { + DOM.releaseCapture(getElement()); + isCapturing = false; + isFocusing = false; } + } - this.width = width; + @Override + public void setWidth(String width) { + if (BrowserInfo.get().isIE6() || BrowserInfo.get().isIE7()) { + if (width != null && width.length() > 2) { + // Assume pixel values are always sent from + // ApplicationConnection + int w = Integer + .parseInt(width.substring(0, width.length() - 2)); + w -= getHorizontalBorderAndPaddingWidth(getElement()); + width = w + "px"; + } + } super.setWidth(width); + } - /* Workaround for IE7 button size part 2 (#2014) */ - if (BrowserInfo.get().isIE7()) { - super.setWidth(width); + private static native int getHorizontalBorderAndPaddingWidth(Element elem) + /*-{ + // THIS METHOD IS ONLY USED FOR INTERNET EXPLORER, IT DOESN'T WORK WITH OTHERS + + var convertToPixel = function(elem, value) { + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // Remember the original values + var left = style.left, rsLeft = elem.runtimeStyle.left; + + // Put in the new values to get a computed value out + elem.runtimeStyle.left = elem.currentStyle.left; + style.left = value || 0; + var ret = style.pixelLeft; + + // Revert the changed values + style.left = left; + elem.runtimeStyle.left = rsLeft; + + return ret; + } + + var ret = 0; + + var sides = ["Right","Left"]; + for(var i=0; i<2; i++) { + var side = sides[i]; + var value; + // Border ------------------------------------------------------- + if(elem.currentStyle["border"+side+"Style"] != "none") { + value = elem.currentStyle["border"+side+"Width"]; + if ( !/^\d+(px)?$/i.test( value ) && /^\d/.test( value ) ) { + ret += convertToPixel(elem, value); + } else if(value.length > 2) { + ret += parseInt(value.substr(0, value.length-2)); + } + } + + // Padding ------------------------------------------------------- + value = elem.currentStyle["padding"+side]; + if ( !/^\d+(px)?$/i.test( value ) && /^\d/.test( value ) ) { + ret += convertToPixel(elem, value); + } else if(value.length > 2) { + ret += parseInt(value.substr(0, value.length-2)); + } } - } + + return ret; + }-*/; } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java index 8d688c2ed9..f1f640653e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java @@ -394,7 +394,8 @@ public class VCalendarPanel extends FlexTable implements MouseListener { processClickEvent(sender, true);
}
- private class VEventButton extends VButton implements SourcesMouseEvents {
+ private class VEventButton extends VNativeButton implements
+ SourcesMouseEvents {
private MouseListenerCollection mouseListeners;
@@ -404,6 +405,7 @@ public class VCalendarPanel extends FlexTable implements MouseListener { | Event.MOUSEEVENTS);
}
+ @Override
public void addMouseListener(MouseListener listener) {
if (mouseListeners == null) {
mouseListeners = new MouseListenerCollection();
@@ -411,6 +413,7 @@ public class VCalendarPanel extends FlexTable implements MouseListener { mouseListeners.add(listener);
}
+ @Override
public void removeMouseListener(MouseListener listener) {
if (mouseListeners != null) {
mouseListeners.remove(listener);
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java b/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java new file mode 100644 index 0000000000..e544e1f9ce --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java @@ -0,0 +1,182 @@ +/* +@ITMillApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.DeferredCommand; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.Button; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VTooltip; + +public class VNativeButton extends Button implements Paintable { + + public static final String CLASSNAME = "v-nativebutton"; + + protected String width = null; + + protected String id; + + protected ApplicationConnection client; + + protected Element errorIndicatorElement; + + protected final Element captionElement = DOM.createSpan(); + + protected Icon icon; + + /** + * Helper flag to handle special-case where the button is moved from under + * mouse while clicking it. In this case mouse leaves the button without + * moving. + */ + private boolean clickPending; + + public VNativeButton() { + setStyleName(CLASSNAME); + + getElement().appendChild(captionElement); + captionElement.setClassName(getStyleName() + "-caption"); + + addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + if (id == null || client == null) { + return; + } + if (BrowserInfo.get().isSafari()) { + VNativeButton.this.setFocus(true); + } + client.updateVariable(id, "state", true, true); + clickPending = false; + } + }); + sinkEvents(VTooltip.TOOLTIP_EVENTS); + sinkEvents(Event.ONMOUSEDOWN); + sinkEvents(Event.ONMOUSEUP); + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + + // Ensure correct implementation, + // but don't let container manage caption etc. + if (client.updateComponent(this, uidl, false)) { + return; + } + + // Save details + this.client = client; + id = uidl.getId(); + + // Set text + setText(uidl.getStringAttribute("caption")); + + // handle error + if (uidl.hasAttribute("error")) { + if (errorIndicatorElement == null) { + errorIndicatorElement = DOM.createSpan(); + errorIndicatorElement.setClassName("v-errorindicator"); + } + getElement().insertBefore(errorIndicatorElement, captionElement); + + // Fix for IE6, IE7 + if (BrowserInfo.get().isIE()) { + errorIndicatorElement.setInnerText(" "); + } + + } else if (errorIndicatorElement != null) { + getElement().removeChild(errorIndicatorElement); + errorIndicatorElement = null; + } + + if (uidl.hasAttribute("icon")) { + if (icon == null) { + icon = new Icon(client); + getElement().insertBefore(icon.getElement(), captionElement); + } + icon.setUri(uidl.getStringAttribute("icon")); + } else { + if (icon != null) { + getElement().removeChild(icon.getElement()); + icon = null; + } + } + + if (BrowserInfo.get().isIE7()) { + /* + * Workaround for IE7 size calculation issues. Deferred because of + * issues with a button with an icon using the reindeer theme + */ + if (width.equals("")) { + DeferredCommand.addCommand(new Command() { + + public void execute() { + setWidth(""); + setWidth(getOffsetWidth() + "px"); + } + }); + } + } + } + + @Override + public void setText(String text) { + captionElement.setInnerText(text); + } + + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + + if (DOM.eventGetType(event) == Event.ONLOAD) { + Util.notifyParentOfSizeChange(this, true); + + } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN + && event.getButton() == Event.BUTTON_LEFT) { + clickPending = true; + } else if (DOM.eventGetType(event) == Event.ONMOUSEMOVE) { + clickPending = false; + } else if (DOM.eventGetType(event) == Event.ONMOUSEOUT) { + if (clickPending) { + click(); + } + clickPending = false; + } + + if (client != null) { + client.handleTooltipEvent(event, this); + } + } + + @Override + public void setWidth(String width) { + /* Workaround for IE7 button size part 1 (#2014) */ + if (BrowserInfo.get().isIE7() && this.width != null) { + if (this.width.equals(width)) { + return; + } + + if (width == null) { + width = ""; + } + } + + this.width = width; + super.setWidth(width); + + /* Workaround for IE7 button size part 2 (#2014) */ + if (BrowserInfo.get().isIE7()) { + super.setWidth(width); + } + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java index d10bcc6cfa..4d4ba4e579 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java @@ -58,7 +58,7 @@ abstract class VOptionGroupBase extends Composite implements Paintable, Field, private VTextField newItemField;
- private VButton newItemButton;
+ private VNativeButton newItemButton;
public VOptionGroupBase(String classname) {
container = new FlowPanel();
@@ -155,7 +155,7 @@ abstract class VOptionGroupBase extends Composite implements Paintable, Field, if (uidl.getBooleanAttribute("allownewitem")) {
if (newItemField == null) {
- newItemButton = new VButton();
+ newItemButton = new VNativeButton();
newItemButton.setText("+");
newItemButton.addClickListener(this);
newItemField = new VTextField();
diff --git a/src/com/vaadin/tests/themes/ButtonsTest.java b/src/com/vaadin/tests/themes/ButtonsTest.java new file mode 100644 index 0000000000..9ad2a9f39e --- /dev/null +++ b/src/com/vaadin/tests/themes/ButtonsTest.java @@ -0,0 +1,158 @@ +package com.vaadin.tests.themes; + +import com.vaadin.terminal.ThemeResource; +import com.vaadin.terminal.UserError; +import com.vaadin.ui.Button; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Layout; +import com.vaadin.ui.NativeButton; +import com.vaadin.ui.Window; +import com.vaadin.ui.Button.ClickEvent; + +@SuppressWarnings("serial") +public class ButtonsTest extends com.vaadin.Application { + + final Window main = new Window("Button states & themes"); + + CheckBox styleToggle; + CheckBox iconToggle; + CheckBox nativeToggle; + CheckBox themeToggle; + boolean largeIcons = false; + boolean nativeButtons = false; + + final HorizontalLayout toggles = new HorizontalLayout(); + + @Override + public void init() { + setMainWindow(main); + setTheme("reindeer"); + + themeToggle = new CheckBox("Runo theme", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + if (getTheme() == "reindeer") { + setTheme("runo"); + } else { + setTheme("reindeer"); + } + } + }); + themeToggle.setStyleName("small"); + themeToggle.setImmediate(true); + + styleToggle = new CheckBox("Black style", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + if (!main.getContent().getStyleName().contains("black")) { + main.getContent().setStyleName("black"); + } else { + main.getContent().setStyleName(""); + } + } + }); + styleToggle.setImmediate(true); + styleToggle.setStyleName("small"); + + iconToggle = new CheckBox("64x icons", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + largeIcons = !largeIcons; + recreateAll(); + } + }); + iconToggle.setImmediate(true); + iconToggle.setStyleName("small"); + + nativeToggle = new CheckBox("Native buttons", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + nativeButtons = !nativeButtons; + recreateAll(); + } + }); + nativeToggle.setImmediate(true); + nativeToggle.setStyleName("small"); + + toggles.setSpacing(true); + toggles.addComponent(themeToggle); + toggles.addComponent(styleToggle); + toggles.addComponent(iconToggle); + toggles.addComponent(nativeToggle); + main.addComponent(toggles); + + recreateAll(); + + } + + private void recreateAll() { + main.removeAllComponents(); + main.addComponent(toggles); + + main.addComponent(buildButtons(false, false, false, false)); + main.addComponent(buildButtons(false, false, true, false)); + main.addComponent(buildButtons(false, true, false, false)); + main.addComponent(buildButtons(false, true, true, false)); + main.addComponent(buildButtons(true, false, false, false)); + main.addComponent(buildButtons(true, false, true, false)); + main.addComponent(buildButtons(true, true, false, false)); + main.addComponent(buildButtons(true, true, true, false)); + + main.addComponent(buildButtons(false, false, false, true)); + main.addComponent(buildButtons(false, false, true, true)); + main.addComponent(buildButtons(false, true, false, true)); + main.addComponent(buildButtons(false, true, true, true)); + main.addComponent(buildButtons(true, false, false, true)); + main.addComponent(buildButtons(true, false, true, true)); + main.addComponent(buildButtons(true, true, false, true)); + main.addComponent(buildButtons(true, true, true, true)); + + final Button b = new Button("Tabindex"); + b.setTabIndex(1); + main.addComponent(b); + + Button c = new Button("toggle enabled", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + b.setEnabled(!b.isEnabled()); + } + }); + main.addComponent(c); + } + + private Layout buildButtons(boolean disabled, boolean icon, boolean error, + boolean sized) { + + String[] buttonStyles = new String[] { "Normal", "Primary", "Small", + "Link" }; + + HorizontalLayout hl = new HorizontalLayout(); + hl.setSpacing(true); + hl.setMargin(true); + + for (int i = 0; i < buttonStyles.length; i++) { + Button b; + if (nativeButtons) { + b = new NativeButton(buttonStyles[i] + " style"); + } else { + b = new Button(buttonStyles[i] + " style"); + } + b.setStyleName(buttonStyles[i].toLowerCase()); + if (icon) { + b.setIcon(new ThemeResource("../runo/icons/" + + (largeIcons ? "64" : "16") + "/document.png")); + } + if (error) { + b.setComponentError(new UserError("Error")); + } + if (disabled) { + b.setEnabled(false); + } + if (sized) { + b.setWidth("250px"); + b.setCaption(b.getCaption() + " (250px)"); + } + hl.addComponent(b); + } + + return hl; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/tests/themes/ReindeerButtonsTest.java b/src/com/vaadin/tests/themes/ReindeerButtonsTest.java deleted file mode 100644 index 952b7ffd1c..0000000000 --- a/src/com/vaadin/tests/themes/ReindeerButtonsTest.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.vaadin.tests.themes; - -import com.vaadin.terminal.ThemeResource; -import com.vaadin.terminal.UserError; -import com.vaadin.ui.Button; -import com.vaadin.ui.HorizontalLayout; -import com.vaadin.ui.Layout; -import com.vaadin.ui.Window; -import com.vaadin.ui.Button.ClickEvent; - -@SuppressWarnings("serial") -public class ReindeerButtonsTest extends com.vaadin.Application { - - final Window main = new Window("Reindeer buttons"); - - @Override - public void init() { - setMainWindow(main); - setTheme("reindeer"); - - Button toggle = new Button("Toggle black style", - new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - if (!main.getContent().getStyleName().contains("black")) { - main.getContent().setStyleName("black"); - } else { - main.getContent().setStyleName(""); - } - } - }); - main.addComponent(toggle); - - main.addComponent(buildButtons(false, false, false, false)); - main.addComponent(buildButtons(false, false, true, false)); - main.addComponent(buildButtons(false, true, false, false)); - main.addComponent(buildButtons(false, true, true, false)); - main.addComponent(buildButtons(true, false, false, false)); - main.addComponent(buildButtons(true, false, true, false)); - main.addComponent(buildButtons(true, true, false, false)); - main.addComponent(buildButtons(true, true, true, false)); - - main.addComponent(buildButtons(false, false, false, true)); - main.addComponent(buildButtons(false, false, true, true)); - main.addComponent(buildButtons(false, true, false, true)); - main.addComponent(buildButtons(false, true, true, true)); - main.addComponent(buildButtons(true, false, false, true)); - main.addComponent(buildButtons(true, false, true, true)); - main.addComponent(buildButtons(true, true, false, true)); - main.addComponent(buildButtons(true, true, true, true)); - } - - private Layout buildButtons(boolean disabled, boolean icon, boolean error, - boolean sized) { - - String[] buttonStyles = new String[] { "", "primary", "small", "link" }; - - HorizontalLayout hl = new HorizontalLayout(); - hl.setSpacing(true); - hl.setMargin(true); - - for (int i = 0; i < buttonStyles.length; i++) { - Button b = new Button(buttonStyles[i] + " style"); - b.setStyleName(buttonStyles[i]); - if (icon) { - b.setIcon(new ThemeResource("../runo/icons/16/document.png")); - } - if (error) { - b.setComponentError(new UserError("Error")); - } - if (disabled) { - b.setEnabled(false); - } - if (sized) { - b.setWidth("150px"); - } - hl.addComponent(b); - } - - return hl; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/ui/Button.java b/src/com/vaadin/ui/Button.java index df40aeb018..e4ca734d34 100644 --- a/src/com/vaadin/ui/Button.java +++ b/src/com/vaadin/ui/Button.java @@ -28,8 +28,6 @@ public class Button extends AbstractField { boolean switchMode = false; - private String primaryStyleName; - /** * Creates a new push button. The value of the push button is false and it * is immediate by default. @@ -137,9 +135,6 @@ public class Button extends AbstractField { public void paintContent(PaintTarget target) throws PaintException { super.paintContent(target); - if (primaryStyleName != null) { - target.addAttribute("primarystyle", primaryStyleName); - } if (isSwitchMode()) { target.addAttribute("type", "switch"); } @@ -352,33 +347,4 @@ public class Button extends AbstractField { super.setInternalValue(newValue); } - /** - * - * <i><b>EXPERIMENTAL FEATURE</b> Use with caution, the method signature - * might change in following releases.</i> - * <p> - * Sets the components primary style name. - * <p> - * The primary style name is usually used on the client-side as the prefix - * for widget CSS classnames (this depends on the terminal implementation). - * The default primary styles are usually prefixed with Vaadin proprietary - * "v-" string, e.g. the primary style name for a default Vaadin button is - * "v-button". - * <p> - * With this method, you can change the primary style name to "mybutton", - * and then on the client-side you would have "mybutton" as the CSS - * classname. After that, all other style names you set for the component - * will be prefixed with the new primary style name, i.e. setting an - * additional style name "red" for the same button would result in a CSS - * classname "mybutton-red" on the client-side. - */ - public void setPrimaryStyleName(String primary) { - primaryStyleName = primary; - requestRepaint(); - } - - public String getPrimaryStyleName() { - return primaryStyleName; - } - } diff --git a/src/com/vaadin/ui/NativeButton.java b/src/com/vaadin/ui/NativeButton.java new file mode 100644 index 0000000000..4df771d054 --- /dev/null +++ b/src/com/vaadin/ui/NativeButton.java @@ -0,0 +1,51 @@ +package com.vaadin.ui; + +import com.vaadin.data.Property; + +@SuppressWarnings("serial") +public class NativeButton extends Button { + + public NativeButton() { + super(); + } + + public NativeButton(String caption) { + super(caption); + } + + public NativeButton(String caption, ClickListener listener) { + super(caption, listener); + } + + public NativeButton(String caption, Object target, String methodName) { + super(caption, target, methodName); + } + + /** + * Creates a new switch button with initial value. + * + * @param state + * the Initial state of the switch-button. + * @param initialState + */ + public NativeButton(String caption, boolean initialState) { + super(caption, initialState); + } + + /** + * Creates a new switch button that is connected to a boolean property. + * + * @param state + * the Initial state of the switch-button. + * @param dataSource + */ + public NativeButton(String caption, Property dataSource) { + super(caption, dataSource); + } + + @Override + public String getTag() { + return "nativebutton"; + } + +}
\ No newline at end of file |