diff options
59 files changed, 6172 insertions, 1222 deletions
diff --git a/WebContent/VAADIN/themes/base/base.scss b/WebContent/VAADIN/themes/base/base.scss index a16b063ba8..640978d316 100644 --- a/WebContent/VAADIN/themes/base/base.scss +++ b/WebContent/VAADIN/themes/base/base.scss @@ -5,6 +5,7 @@ @import "button/checkbox.scss"; @import "layout/layout.scss"; @import "caption/caption.scss"; +@import "colorpicker/colorpicker.scss"; @import "common/common.scss"; @import "csslayout/csslayout.scss"; @import "customcomponent/customcomponent.scss"; @@ -61,6 +62,7 @@ @include base-nativebutton; @include base-checkbox; @include base-caption; + @include base-colorpicker; // here for now to preserve old semantics @include base-common; diff --git a/WebContent/VAADIN/themes/base/colorpicker/colorpicker.scss b/WebContent/VAADIN/themes/base/colorpicker/colorpicker.scss new file mode 100644 index 0000000000..bd4420b55b --- /dev/null +++ b/WebContent/VAADIN/themes/base/colorpicker/colorpicker.scss @@ -0,0 +1,209 @@ +@mixin base-colorpicker($name : v-colorpicker) { + +.#{$name} { + text-align: center; +} + +.#{$name}-button-color { + border: 1px solid silver; + float: left; + width: 10px; + height: 10px; + margin-top: 2px; + margin-right: 5px; +} + +.#{$name}-area { + border: 1px solid silver; + margin: 1px auto; +} + + +/***************** COLOR HISTORY COMPONENT *****************************/ +.#{$name}-history { + margin: 5px; +} + +.#{$name}-history td { + border: 1px solid silver !important; +} + +.#{$name}-history td { + line-height: 15px; +} +/***********************************************************************/ + + +/**************** COLOR POPUP COMPONENT ********************************/ +.#{$name}-popup { + width: 244px; +} + +.#{$name}-popup .v-scrollable { + background-color: #dddddd; +} + +.#{$name}-popup .v-tabsheet-content .v-scrollable { + background-color: #eaeaea; +} + +.#{$name}-popup .v-tabsheet-content .v-tabsheet-tabsheetpanel { + background: transparent; +} + +.#{$name}-popup .resize-button { + border: 0px solid silver; + background: url(images/resizebg.png); + margin-top: 5px; +} + +.#{$name}-popup .resize-button-caption { + display: none; +} + +.#{$name}-popup .resize-button:hover { + background: url(images/resizebg-selected.png); +} + +.#{$name}-popup .resize-button:focus { + outline: none; +} + +/***********************************************************************/ + + +/*********************** COLOR GRADIENT *******************************/ +.#{$name}-gradient { + width: 220px; + height: 220px; + padding-left: 10px; + margin-top: 0px; +} + +.#{$name}-gradient .#{$name}-gradient-clicklayer { + background-color: white; + filter: alpha(opacity = 0); + opacity: 0; +} + +.#{$name}-popup #rgb-gradient .#{$name}-gradient-background { + width: 220px; + height: 220px; + background: url(images/gradient2.png); +} + +.#{$name}-popup #hsv-gradient .#{$name}-gradient-foreground { + background: url(images/gradient.png); +} + +.#{$name}-popup .#{$name}-gradient-lowerbox { + border-right: 1px solid white; + border-top: 1px solid white; +} + +.#{$name}-popup .#{$name}-gradient-higherbox { + border-left: 1px solid white; + border-bottom: 1px solid white; +} +/**********************************************************************/ + + +/************************ COLOR SLIDER ********************************/ +.#{$name}-popup .rgb-sliders { + width: 227px; + padding-left: 10px; + color: #444444; + text-shadow: 0 1px 0 #FFFFFF; +} + +.#{$name}-popup .rgb-sliders .red .v-slider-base { + background-color: red; +} + +.#{$name}-popup .rgb-sliders .green .v-slider-base { + background-color: green; +} + +.#{$name}-popup .rgb-sliders .blue .v-slider-base { + background-color: blue; +} + +.#{$name}-popup .hsv-sliders { + padding-left: 10px; + color: #444444; + text-shadow: 0 1px 0 #FFFFFF; +} + +.#{$name}-popup .hue-slider { + height: 10px; + border: 0px solid silver; + background-image: url(images/slider_hue_bg.png); + background-color: transparent; + background-repeat: no-repeat; + background-position: 0 3px; + margin-top: 0px; +} + +.#{$name}-popup .hue-slider .v-slider-handle { + margin-top: -2px; +} + +.#{$name}-popup .hue-slider .v-slider-base { + border: 0px none; + height: 0px; + background-color: transparent; +} +/****************************************************************/ + + +/****************** COLOR PREVIEW *******************************/ +.#{$name}-popup .#{$name}-preview { + margin-top: 5px; + padding-left: 11px; + padding-right: 10px; + margin-bottom: 0px; +} + +.#{$name}-popup .v-absolutelayout-wrapper { + width: 100%; + height: 100%; +} + +.#{$name}-popup .#{$name}-preview-textfield { + background: none; + overflow: hidden; + overflow-y: hidden; + overflow-x: hidden; +} + +.#{$name}-popup .v-textfield-dark { + color: #FFFFFF; +} + +.#{$name}-popup .v-textfield-light { + color: #000000; +} +/****************************************************************/ + + +/*************** COLOR SELECT ***********************************/ +.#{$name}-popup .colorselect { + margin-top: 5px; + padding-left: 10px; + padding-right: 10px; +} + +.#{$name}-popup .v-tabsheet .#{$name}-grid { + height: 319px; +} + +.#{$name}-popup .colorselect td { + line-height: 15px; +} + +.#{$name}-popup .v-filterselect { + padding-right: 16px; +} +/****************************************************************/ + +}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/colorpicker/images/gradient.png b/WebContent/VAADIN/themes/base/colorpicker/images/gradient.png Binary files differnew file mode 100644 index 0000000000..def063a8ab --- /dev/null +++ b/WebContent/VAADIN/themes/base/colorpicker/images/gradient.png diff --git a/WebContent/VAADIN/themes/base/colorpicker/images/gradient2.png b/WebContent/VAADIN/themes/base/colorpicker/images/gradient2.png Binary files differnew file mode 100644 index 0000000000..f51ed752a7 --- /dev/null +++ b/WebContent/VAADIN/themes/base/colorpicker/images/gradient2.png diff --git a/WebContent/VAADIN/themes/base/colorpicker/images/resizebg-selected.png b/WebContent/VAADIN/themes/base/colorpicker/images/resizebg-selected.png Binary files differnew file mode 100644 index 0000000000..6e56ec0cc7 --- /dev/null +++ b/WebContent/VAADIN/themes/base/colorpicker/images/resizebg-selected.png diff --git a/WebContent/VAADIN/themes/base/colorpicker/images/resizebg.png b/WebContent/VAADIN/themes/base/colorpicker/images/resizebg.png Binary files differnew file mode 100644 index 0000000000..b6e3532713 --- /dev/null +++ b/WebContent/VAADIN/themes/base/colorpicker/images/resizebg.png diff --git a/WebContent/VAADIN/themes/base/colorpicker/images/slider_hue_bg.png b/WebContent/VAADIN/themes/base/colorpicker/images/slider_hue_bg.png Binary files differnew file mode 100644 index 0000000000..bcef2c5575 --- /dev/null +++ b/WebContent/VAADIN/themes/base/colorpicker/images/slider_hue_bg.png diff --git a/WebContent/VAADIN/themes/base/datefield/datefield.scss b/WebContent/VAADIN/themes/base/datefield/datefield.scss index dcefe27f09..e6309aadd3 100644 --- a/WebContent/VAADIN/themes/base/datefield/datefield.scss +++ b/WebContent/VAADIN/themes/base/datefield/datefield.scss @@ -8,6 +8,10 @@ .#{$primaryStyleName}-textfield { vertical-align: top; } +.v-ie & .#{$primaryStyleName}-button:after { + content: "\200B"; +} + .#{$primaryStyleName}-button { cursor: pointer; } diff --git a/WebContent/VAADIN/themes/chameleon/components/colorpicker/colorpicker.scss b/WebContent/VAADIN/themes/chameleon/components/colorpicker/colorpicker.scss new file mode 100644 index 0000000000..98f00f0626 --- /dev/null +++ b/WebContent/VAADIN/themes/chameleon/components/colorpicker/colorpicker.scss @@ -0,0 +1,15 @@ +@mixin chameleon-colorpicker($name : v-colorpicker) { + +.#{$name}-button-color { + border: 1px solid #8B8B8B; +} + +.#{$name}-popup { + width: 248px; +} + +.#{$name}-popup .v-tabsheet .#{$name}-grid { + height: 308px; +} + +}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/chameleon/components/components.scss b/WebContent/VAADIN/themes/chameleon/components/components.scss index 79b5a2d468..9f29827de0 100644 --- a/WebContent/VAADIN/themes/chameleon/components/components.scss +++ b/WebContent/VAADIN/themes/chameleon/components/components.scss @@ -1,5 +1,6 @@ @import "accordion/accordion.scss"; @import "button/button.scss"; +@import "colorpicker/colorpicker.scss"; @import "label/label.scss"; @import "menubar/menubar.scss"; @import "notification/notification.scss"; @@ -22,6 +23,7 @@ @include chameleon-accordion; @include chameleon-button; + @include chameleon-colorpicker; @include chameleon-label; @include chameleon-menubar; @include chameleon-notification; diff --git a/WebContent/VAADIN/themes/liferay/colorpicker/colorpicker.scss b/WebContent/VAADIN/themes/liferay/colorpicker/colorpicker.scss new file mode 100644 index 0000000000..fc50297388 --- /dev/null +++ b/WebContent/VAADIN/themes/liferay/colorpicker/colorpicker.scss @@ -0,0 +1,19 @@ +@mixin liferay-colorpicker($name : v-colorpicker) { + +.#{$name}-button-color { + border: 1px solid #999999; +} + +.#{$name}-popup { + width: 252px; +} + +.#{$name}-popup .v-tabsheet .#{$name}-grid { + height: 312px; +} + +.#{$name}-popup .v-filterselect { + padding-right: 24px; +} + +}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/liferay/liferay.scss b/WebContent/VAADIN/themes/liferay/liferay.scss index 3128e48c76..299542fea0 100644 --- a/WebContent/VAADIN/themes/liferay/liferay.scss +++ b/WebContent/VAADIN/themes/liferay/liferay.scss @@ -2,6 +2,7 @@ @import "accordion/accordion.scss"; @import "button/button.scss"; +@import "colorpicker/colorpicker.scss"; @import "common/common.scss"; @@ -29,6 +30,7 @@ // TODO @each @include liferay-accordion; @include liferay-button; + @include liferay-colorpicker; @include liferay-common; @include liferay-contextmenu; diff --git a/WebContent/VAADIN/themes/reindeer/colorpicker/colorpicker.scss b/WebContent/VAADIN/themes/reindeer/colorpicker/colorpicker.scss new file mode 100644 index 0000000000..4224691d12 --- /dev/null +++ b/WebContent/VAADIN/themes/reindeer/colorpicker/colorpicker.scss @@ -0,0 +1,15 @@ +@mixin reindeer-colorpicker($name : v-colorpicker) { + +.#{$name}-popup { + width: 246px; +} + +.#{$name}-popup .v-tabsheet .#{$name}-grid { + height: 284px; +} + +.#{$name}-popup .v-filterselect { + padding-right: 25px; +} + +}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/reindeer/reindeer.scss b/WebContent/VAADIN/themes/reindeer/reindeer.scss index ce6b54610e..f02fcf18a8 100644 --- a/WebContent/VAADIN/themes/reindeer/reindeer.scss +++ b/WebContent/VAADIN/themes/reindeer/reindeer.scss @@ -5,6 +5,7 @@ @import "a-sprite-definitions/a-sprite-definitions.scss"; @import "button/button.scss"; @import "button/nativebutton.scss"; +@import "colorpicker/colorpicker.scss"; @import "common/common.scss"; @@ -42,6 +43,7 @@ // TODO @include a-sprite-definitions; @include reindeer-button; @include reindeer-nativebutton; + @include reindeer-colorpicker; @include reindeer-common; @include reindeer-datefield; @include reindeer-inlinedatefield; diff --git a/WebContent/VAADIN/themes/runo/colorpicker/colorpicker.scss b/WebContent/VAADIN/themes/runo/colorpicker/colorpicker.scss new file mode 100644 index 0000000000..df48c10a86 --- /dev/null +++ b/WebContent/VAADIN/themes/runo/colorpicker/colorpicker.scss @@ -0,0 +1,20 @@ +@mixin runo-colorpicker($name : v-colorpicker) { + +.#{$name}-popup { + width: 248px; +} + +.#{$name}-popup .v-tabsheet .#{$name}-grid { + height: 305px; +} + +.#{$name}-popup .v-tabsheet-deco { + background: none; + height: 0; +} + +.#{$name}-popup .v-filterselect { + padding-right: 25px; +} + +}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/runo/runo.scss b/WebContent/VAADIN/themes/runo/runo.scss index de4d2b3bbd..395f4d0b1b 100644 --- a/WebContent/VAADIN/themes/runo/runo.scss +++ b/WebContent/VAADIN/themes/runo/runo.scss @@ -4,6 +4,7 @@ @import "accordion/accordion.scss"; @import "button/button.scss"; @import "caption/caption.scss"; +@import "colorpicker/colorpicker.scss"; @import "common/common.scss"; @import "datefield/datefield.scss"; @import "inlinedatefield/inlinedatefield.scss"; @@ -39,6 +40,7 @@ @include runo-accordion; @include runo-button; @include runo-caption; + @include runo-colorpicker; @include runo-common; @@ -63,4 +65,4 @@ @include runo-textfield; @include runo-tree; @include runo-window; -}
\ No newline at end of file +} diff --git a/client/src/com/vaadin/client/ComponentLocator.java b/client/src/com/vaadin/client/ComponentLocator.java index 854c8535c4..249c3f78f4 100644 --- a/client/src/com/vaadin/client/ComponentLocator.java +++ b/client/src/com/vaadin/client/ComponentLocator.java @@ -29,10 +29,10 @@ import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ui.SubPartAware; import com.vaadin.client.ui.VCssLayout; import com.vaadin.client.ui.VGridLayout; -import com.vaadin.client.ui.VOrderedLayout; import com.vaadin.client.ui.VTabsheetPanel; import com.vaadin.client.ui.VUI; import com.vaadin.client.ui.VWindow; +import com.vaadin.client.ui.orderedlayout.VAbstractOrderedLayout; import com.vaadin.client.ui.window.WindowConnector; import com.vaadin.shared.AbstractComponentState; import com.vaadin.shared.Connector; @@ -315,7 +315,7 @@ public class ComponentLocator { String childIndexString = part.substring("domChild[".length(), part.length() - 1); - if (Util.findWidget(baseElement, null) instanceof VOrderedLayout) { + if (Util.findWidget(baseElement, null) instanceof VAbstractOrderedLayout) { if (element.hasChildNodes()) { Element e = element.getFirstChildElement().cast(); String cn = e.getClassName(); @@ -563,10 +563,10 @@ public class ComponentLocator { } // ChildComponentContainer has been removed and replaced with - // VOrderLayout.Slot's - if (w instanceof VOrderedLayout + // Slot + if (w instanceof VAbstractOrderedLayout && "ChildComponentContainer".equals(widgetClassName)) { - widgetClassName = "VOrderedLayout$Slot"; + widgetClassName = "Slot"; } if (w instanceof VTabsheetPanel && widgetPosition != 0) { @@ -662,8 +662,8 @@ public class ComponentLocator { } widgetPosition--; - } else if (w instanceof VOrderedLayout - && "VOrderedLayout$Slot".equals(simpleName2)) { + } else if (w instanceof VAbstractOrderedLayout + && "Slot".equals(simpleName2)) { child = ((SimplePanel) child).getWidget(); simpleName2 = Util.getSimpleName(child); if (widgetClassName.equals(simpleName2)) { diff --git a/client/src/com/vaadin/client/ui/VColorPicker.java b/client/src/com/vaadin/client/ui/VColorPicker.java new file mode 100644 index 0000000000..7cd5fbfed7 --- /dev/null +++ b/client/src/com/vaadin/client/ui/VColorPicker.java @@ -0,0 +1,73 @@ +package com.vaadin.client.ui; + +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.ui.HTML; + +/** + * Client side implementation for ColorPicker. + * + * @since 7.0.0 + */ +public class VColorPicker extends VButton implements ClickHandler { + + private String color = null; + + private boolean isOpen = false; + + private HTML colorIcon; + + @Override + public void onClick(ClickEvent event) { + super.onClick(event); + + setOpen(!isOpen); + } + + /** + * Set the color of the component, e.g. #ffffff + * + * @param color + */ + public void setColor(String color) { + this.color = color; + } + + /** + * Mark the popup opened/closed. + * + * @param open + */ + public void setOpen(boolean open) { + isOpen = open; + } + + /** + * Check the popup's marked state. + * + * @return true if the popup has been marked being open, false otherwise. + */ + public boolean isOpen() { + return isOpen; + } + + /** + * Update color icon to show the currently selected color. + */ + public void refreshColor() { + if (color != null) { + + if (colorIcon == null) { + colorIcon = new HTML(); + colorIcon.setStylePrimaryName("v-colorpicker-button-color"); + wrapper.insertBefore(colorIcon.getElement(), captionElement); + } + + // Set the color + DOM.setStyleAttribute(colorIcon.getElement(), "background", color); + + } + } + +} diff --git a/client/src/com/vaadin/client/ui/VColorPickerArea.java b/client/src/com/vaadin/client/ui/VColorPickerArea.java new file mode 100644 index 0000000000..2327b79f8a --- /dev/null +++ b/client/src/com/vaadin/client/ui/VColorPickerArea.java @@ -0,0 +1,181 @@ +package com.vaadin.client.ui; + +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.HasClickHandlers; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.HasHTML; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.Widget; + +/** + * Client side implementation for ColorPickerArea. + * + * @since 7.0.0 + */ +public class VColorPickerArea extends Widget implements ClickHandler, HasHTML, + HasClickHandlers { + + private String color = null; + + private boolean isOpen; + + private HTML caption; + private HTML area; + + /** + * Initializes an area-style color picker widget. + */ + public VColorPickerArea() { + super(); + setElement(DOM.createDiv()); + + caption = new HTML(); + caption.addStyleName("v-caption"); + caption.setWidth(""); + + area = new HTML(); + area.setStylePrimaryName(getStylePrimaryName() + "-area"); + + getElement().appendChild(caption.getElement()); + getElement().appendChild(area.getElement()); + + addClickHandler(this); + } + + /** + * Adds a click handler to the widget and sinks the click event. + * + * @param handler + * @return HandlerRegistration used to remove the handler + */ + public HandlerRegistration addClickHandler(ClickHandler handler) { + return addDomHandler(handler, ClickEvent.getType()); + } + + @Override + public void onClick(ClickEvent event) { + setOpen(!isOpen); + } + + @Override + public void onBrowserEvent(Event event) { + int type = DOM.eventGetType(event); + switch (type) { + case Event.ONCLICK: + if (DOM.isOrHasChild(area.getElement(), DOM.eventGetTarget(event))) { + super.onBrowserEvent(event); + } + break; + default: + super.onBrowserEvent(event); + } + } + + /** + * Mark the popup opened/closed. + * + * @param open + */ + public void setOpen(boolean open) { + isOpen = open; + } + + /** + * Check the popup's marked state. + * + * @return true if the popup has been marked being open, false otherwise. + */ + public boolean isOpen() { + return isOpen; + } + + /** + * Sets the caption's content to the given text. + * + * @param text + * + * @see Label#setText(String) + */ + @Override + public void setText(String text) { + caption.setText(text); + } + + /** + * Gets the caption's contents as text. + * + * @return the caption's text + */ + @Override + public String getText() { + return caption.getText(); + } + + /** + * Sets the caption's content to the given HTML. + * + * @param html + */ + @Override + public void setHTML(String html) { + caption.setHTML(html); + } + + /** + * Gets the caption's contents as HTML. + * + * @return the caption's HTML + */ + @Override + public String getHTML() { + return caption.getHTML(); + } + + /** + * Sets the color for the area. + * + * @param color + */ + public void setColor(String color) { + this.color = color; + } + + /** + * Update the color area with the currently set color. + */ + public void refreshColor() { + if (color != null) { + // Set the color + DOM.setStyleAttribute(area.getElement(), "background", color); + } + } + + @Override + public void setStylePrimaryName(String style) { + super.setStylePrimaryName(style); + area.setStylePrimaryName(getStylePrimaryName() + "-area"); + } + + /** + * Sets the color area's height. This height does not include caption or + * decorations such as border, margin, and padding. + */ + @Override + public void setHeight(String height) { + area.setHeight(height); + } + + /** + * Sets the color area's width. This width does not include caption or + * decorations such as border, margin, and padding. + */ + @Override + public void setWidth(String width) { + area.setWidth(width); + } + +} diff --git a/client/src/com/vaadin/client/ui/VHorizontalLayout.java b/client/src/com/vaadin/client/ui/VHorizontalLayout.java index 53a933e374..a75e681bcf 100644 --- a/client/src/com/vaadin/client/ui/VHorizontalLayout.java +++ b/client/src/com/vaadin/client/ui/VHorizontalLayout.java @@ -16,11 +16,12 @@ package com.vaadin.client.ui; import com.vaadin.client.StyleConstants; +import com.vaadin.client.ui.orderedlayout.VAbstractOrderedLayout; /** * Represents a layout where the children is ordered vertically */ -public class VHorizontalLayout extends VOrderedLayout { +public class VHorizontalLayout extends VAbstractOrderedLayout { public static final String CLASSNAME = "v-horizontallayout"; diff --git a/client/src/com/vaadin/client/ui/VOrderedLayout.java b/client/src/com/vaadin/client/ui/VOrderedLayout.java deleted file mode 100644 index bbcb2f85a4..0000000000 --- a/client/src/com/vaadin/client/ui/VOrderedLayout.java +++ /dev/null @@ -1,1196 +0,0 @@ -/* - * Copyright 2011 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.client.ui; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.google.gwt.dom.client.Node; -import com.google.gwt.dom.client.Style; -import com.google.gwt.dom.client.Style.Unit; -import com.google.gwt.regexp.shared.MatchResult; -import com.google.gwt.regexp.shared.RegExp; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.SimplePanel; -import com.google.gwt.user.client.ui.UIObject; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.client.LayoutManager; -import com.vaadin.client.StyleConstants; -import com.vaadin.client.Util; -import com.vaadin.client.ui.layout.ElementResizeListener; -import com.vaadin.shared.ui.AlignmentInfo; -import com.vaadin.shared.ui.MarginInfo; - -/** - * Base class for ordered layouts - */ -public class VOrderedLayout extends FlowPanel { - - private static final String ALIGN_CLASS_PREFIX = "v-align-"; - - protected boolean spacing = false; - - /** For internal use only. May be removed or replaced in the future. */ - public boolean vertical = true; - - protected boolean definedHeight = false; - - private Map<Widget, Slot> widgetToSlot = new HashMap<Widget, Slot>(); - - private Element expandWrapper; - - private LayoutManager layoutManager; - - public VOrderedLayout(boolean vertical) { - this.vertical = vertical; - } - - /** - * Add or move a slot to another index. - * <p> - * For internal use only. May be removed or replaced in the future. - * <p> - * You should note that the index does not refer to the DOM index if - * spacings are used. If spacings are used then the index will be adjusted - * to include the spacings when inserted. - * <p> - * For instance when using spacing the index converts to DOM index in the - * following way: - * - * <pre> - * index : 0 -> DOM index: 0 - * index : 1 -> DOM index: 1 - * index : 2 -> DOM index: 3 - * index : 3 -> DOM index: 5 - * index : 4 -> DOM index: 7 - * </pre> - * - * When using this method never account for spacings. - * </p> - * - * @param slot - * The slot to move or add - * @param index - * The index where the slot should be placed. - */ - public void addOrMoveSlot(Slot slot, int index) { - if (slot.getParent() == this) { - int currentIndex = getWidgetIndex(slot); - if (index == currentIndex) { - return; - } - } - - insert(slot, index); - - /* - * We need to confirm spacings are correctly applied after each insert. - */ - setSpacing(spacing); - } - - /** - * {@inheritDoc} - */ - @Override - protected void insert(Widget child, Element container, int beforeIndex, - boolean domInsert) { - // Validate index; adjust if the widget is already a child of this - // panel. - beforeIndex = adjustIndex(child, beforeIndex); - - // Detach new child. - child.removeFromParent(); - - // Logical attach. - getChildren().insert(child, beforeIndex); - - // Physical attach. - container = expandWrapper != null ? expandWrapper : getElement(); - if (domInsert) { - if (spacing) { - if (beforeIndex != 0) { - /* - * Since the spacing elements are located at the same DOM - * level as the slots we need to take them into account when - * calculating the slot position. - * - * The spacing elements are always located before the actual - * slot except for the first slot which do not have a - * spacing element like this - * - * |<slot1><spacing2><slot2><spacing3><slot3>...| - */ - beforeIndex = beforeIndex * 2 - 1; - } - } - DOM.insertChild(container, child.getElement(), beforeIndex); - } else { - DOM.appendChild(container, child.getElement()); - } - - // Adopt. - adopt(child); - } - - /** - * Remove a slot from the layout - * - * @param widget - * @return - */ - public void removeWidget(Widget widget) { - Slot slot = widgetToSlot.get(widget); - remove(slot); - widgetToSlot.remove(widget); - } - - /** - * Get the containing slot for a widget. If no slot is found a new slot is - * created and returned. - * - * @param widget - * The widget whose slot you want to get - * - * @return - */ - public Slot getSlot(Widget widget) { - Slot slot = widgetToSlot.get(widget); - if (slot == null) { - slot = new Slot(widget); - widgetToSlot.put(widget, slot); - } - return slot; - } - - /** - * Gets a slot based on the widget element. If no slot is found then null is - * returned. - * - * @param widgetElement - * The element of the widget ( Same as getWidget().getElement() ) - * @return - */ - public Slot getSlot(Element widgetElement) { - for (Map.Entry<Widget, Slot> entry : widgetToSlot.entrySet()) { - if (entry.getKey().getElement() == widgetElement) { - return entry.getValue(); - } - } - return null; - } - - /** - * Defines where the caption should be placed - */ - public enum CaptionPosition { - TOP, RIGHT, BOTTOM, LEFT - } - - /** - * Represents a slot which contains the actual widget in the layout. - */ - public final class Slot extends SimplePanel { - - public static final String SLOT_CLASSNAME = "v-slot"; - - private Element spacer; - private Element captionWrap; - private Element caption; - private Element captionText; - private Icon icon; - private Element errorIcon; - private Element requiredIcon; - - private ElementResizeListener captionResizeListener; - - private ElementResizeListener widgetResizeListener; - - private ElementResizeListener spacingResizeListener; - - // Caption is placed after component unless there is some part which - // moves it above. - private CaptionPosition captionPosition = CaptionPosition.RIGHT; - - private AlignmentInfo alignment; - - private double expandRatio = -1; - - /** - * Constructor - * - * @param widget - * The widget to put in the slot - * - * @param layoutManager - * The layout manager used by the layout - */ - private Slot(Widget widget) { - setStyleName(SLOT_CLASSNAME); - setWidget(widget); - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.user.client.ui.SimplePanel#remove(com.google.gwt.user - * .client.ui.Widget) - */ - @Override - public boolean remove(Widget w) { - detachListeners(); - return super.remove(w); - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.user.client.ui.SimplePanel#setWidget(com.google.gwt - * .user.client.ui.Widget) - */ - @Override - public void setWidget(Widget w) { - detachListeners(); - super.setWidget(w); - attachListeners(); - } - - /** - * Attached resize listeners to the widget, caption and spacing elements - */ - private void attachListeners() { - if (getWidget() != null && getLayoutManager() != null) { - LayoutManager lm = getLayoutManager(); - if (getCaptionElement() != null - && captionResizeListener != null) { - lm.addElementResizeListener(getCaptionElement(), - captionResizeListener); - } - if (widgetResizeListener != null) { - lm.addElementResizeListener(getWidget().getElement(), - widgetResizeListener); - } - if (getSpacingElement() != null - && spacingResizeListener != null) { - lm.addElementResizeListener(getSpacingElement(), - spacingResizeListener); - } - } - } - - /** - * Detaches resize listeners from the widget, caption and spacing - * elements - */ - private void detachListeners() { - if (getWidget() != null && getLayoutManager() != null) { - LayoutManager lm = getLayoutManager(); - if (getCaptionElement() != null - && captionResizeListener != null) { - lm.removeElementResizeListener(getCaptionElement(), - captionResizeListener); - } - if (widgetResizeListener != null) { - lm.removeElementResizeListener(getWidget().getElement(), - widgetResizeListener); - } - if (getSpacingElement() != null - && spacingResizeListener != null) { - lm.removeElementResizeListener(getSpacingElement(), - spacingResizeListener); - } - } - } - - public ElementResizeListener getCaptionResizeListener() { - return captionResizeListener; - } - - public void setCaptionResizeListener( - ElementResizeListener captionResizeListener) { - detachListeners(); - this.captionResizeListener = captionResizeListener; - attachListeners(); - } - - public ElementResizeListener getWidgetResizeListener() { - return widgetResizeListener; - } - - public void setWidgetResizeListener( - ElementResizeListener widgetResizeListener) { - detachListeners(); - this.widgetResizeListener = widgetResizeListener; - attachListeners(); - } - - public ElementResizeListener getSpacingResizeListener() { - return spacingResizeListener; - } - - public void setSpacingResizeListener( - ElementResizeListener spacingResizeListener) { - detachListeners(); - this.spacingResizeListener = spacingResizeListener; - attachListeners(); - } - - /** - * Returns the alignment for the slot - * - */ - public AlignmentInfo getAlignment() { - return alignment; - } - - /** - * Sets the style names for the slot containing the widget - * - * @param stylenames - * The style names for the slot - */ - protected void setStyleNames(String... stylenames) { - setStyleName(SLOT_CLASSNAME); - if (stylenames != null) { - for (String stylename : stylenames) { - addStyleDependentName(stylename); - } - } - - // Ensure alignment style names are correct - setAlignment(alignment); - } - - /** - * Sets how the widget is aligned inside the slot - * - * @param alignment - * The alignment inside the slot - */ - public void setAlignment(AlignmentInfo alignment) { - this.alignment = alignment; - - if (alignment != null && alignment.isHorizontalCenter()) { - addStyleName(ALIGN_CLASS_PREFIX + "center"); - removeStyleName(ALIGN_CLASS_PREFIX + "right"); - } else if (alignment != null && alignment.isRight()) { - addStyleName(ALIGN_CLASS_PREFIX + "right"); - removeStyleName(ALIGN_CLASS_PREFIX + "center"); - } else { - removeStyleName(ALIGN_CLASS_PREFIX + "right"); - removeStyleName(ALIGN_CLASS_PREFIX + "center"); - } - - if (alignment != null && alignment.isVerticalCenter()) { - addStyleName(ALIGN_CLASS_PREFIX + "middle"); - removeStyleName(ALIGN_CLASS_PREFIX + "bottom"); - } else if (alignment != null && alignment.isBottom()) { - addStyleName(ALIGN_CLASS_PREFIX + "bottom"); - removeStyleName(ALIGN_CLASS_PREFIX + "middle"); - } else { - removeStyleName(ALIGN_CLASS_PREFIX + "middle"); - removeStyleName(ALIGN_CLASS_PREFIX + "bottom"); - } - } - - /** - * Set how the slot should be expanded relative to the other slots - * - * @param expandRatio - * The ratio of the space the slot should occupy - * - */ - public void setExpandRatio(double expandRatio) { - this.expandRatio = expandRatio; - } - - /** - * Get the expand ratio for the slot. The expand ratio describes how the - * slot should be resized compared to other slots in the layout - * - * @return - */ - public double getExpandRatio() { - return expandRatio; - } - - /** - * Set the spacing for the slot. The spacing determines if there should - * be empty space around the slot when the slot. - * - * @param spacing - * Should spacing be enabled - */ - public void setSpacing(boolean spacing) { - if (spacing && spacer == null) { - spacer = DOM.createDiv(); - spacer.addClassName("v-spacing"); - - /* - * This has to be done here for the initial render. In other - * cases where the spacer already exists onAttach will handle - * it. - */ - getElement().getParentElement().insertBefore(spacer, - getElement()); - } else if (!spacing && spacer != null) { - spacer.removeFromParent(); - spacer = null; - } - } - - /** - * Get the element which is added to make the spacing - * - * @return - */ - public Element getSpacingElement() { - return spacer; - } - - /** - * Does the slot have spacing - */ - public boolean hasSpacing() { - return getSpacingElement() != null; - } - - /** - * Get the vertical amount in pixels of the spacing - */ - protected int getVerticalSpacing() { - if (spacer == null) { - return 0; - } else if (getLayoutManager() != null) { - return getLayoutManager().getOuterHeight(spacer); - } - return spacer.getOffsetHeight(); - } - - /** - * Get the horizontal amount of pixels of the spacing - * - * @return - */ - protected int getHorizontalSpacing() { - if (spacer == null) { - return 0; - } else if (getLayoutManager() != null) { - return getLayoutManager().getOuterWidth(spacer); - } - return spacer.getOffsetWidth(); - } - - /** - * Set the position of the caption relative to the slot - * - * @param captionPosition - * The position of the caption - */ - public void setCaptionPosition(CaptionPosition captionPosition) { - if (caption == null) { - return; - } - captionWrap.removeClassName("v-caption-on-" - + this.captionPosition.name().toLowerCase()); - - this.captionPosition = captionPosition; - if (captionPosition == CaptionPosition.BOTTOM - || captionPosition == CaptionPosition.RIGHT) { - captionWrap.appendChild(caption); - } else { - captionWrap.insertFirst(caption); - } - - captionWrap.addClassName("v-caption-on-" - + captionPosition.name().toLowerCase()); - } - - /** - * Get the position of the caption relative to the slot - */ - public CaptionPosition getCaptionPosition() { - return captionPosition; - } - - /** - * Set the caption of the slot - * - * @param captionText - * The text of the caption - * @param iconUrl - * The icon URL - * @param styles - * The style names - * @param error - * The error message - * @param showError - * Should the error message be shown - * @param required - * Is the (field) required - * @param enabled - * Is the component enabled - */ - public void setCaption(String captionText, String iconUrl, - List<String> styles, String error, boolean showError, - boolean required, boolean enabled) { - - // TODO place for optimization: check if any of these have changed - // since last time, and only run those changes - - // Caption wrappers - if (captionText != null || iconUrl != null || error != null - || required) { - if (caption == null) { - caption = DOM.createDiv(); - captionWrap = DOM.createDiv(); - captionWrap.addClassName(StyleConstants.UI_WIDGET); - captionWrap.addClassName("v-has-caption"); - getElement().appendChild(captionWrap); - captionWrap.appendChild(getWidget().getElement()); - } - } else if (caption != null) { - getElement().appendChild(getWidget().getElement()); - captionWrap.removeFromParent(); - caption = null; - captionWrap = null; - } - - // Caption text - if (captionText != null) { - if (this.captionText == null) { - this.captionText = DOM.createSpan(); - this.captionText.addClassName("v-captiontext"); - caption.appendChild(this.captionText); - } - if (captionText.trim().equals("")) { - this.captionText.setInnerHTML(" "); - } else { - this.captionText.setInnerText(captionText); - } - } else if (this.captionText != null) { - this.captionText.removeFromParent(); - this.captionText = null; - } - - // Icon - if (iconUrl != null) { - if (icon == null) { - icon = new Icon(); - caption.insertFirst(icon.getElement()); - } - icon.setUri(iconUrl); - } else if (icon != null) { - icon.getElement().removeFromParent(); - icon = null; - } - - // Required - if (required) { - if (requiredIcon == null) { - requiredIcon = DOM.createSpan(); - // TODO decide something better (e.g. use CSS to insert the - // character) - requiredIcon.setInnerHTML("*"); - requiredIcon.setClassName("v-required-field-indicator"); - } - caption.appendChild(requiredIcon); - } else if (requiredIcon != null) { - requiredIcon.removeFromParent(); - requiredIcon = null; - } - - // Error - if (error != null && showError) { - if (errorIcon == null) { - errorIcon = DOM.createSpan(); - errorIcon.setClassName("v-errorindicator"); - } - caption.appendChild(errorIcon); - } else if (errorIcon != null) { - errorIcon.removeFromParent(); - errorIcon = null; - } - - if (caption != null) { - // Styles - caption.setClassName("v-caption"); - - if (styles != null) { - for (String style : styles) { - caption.addClassName("v-caption-" + style); - } - } - - if (enabled) { - caption.removeClassName("v-disabled"); - } else { - caption.addClassName("v-disabled"); - } - - // Caption position - if (captionText != null || iconUrl != null) { - setCaptionPosition(CaptionPosition.TOP); - } else { - setCaptionPosition(CaptionPosition.RIGHT); - } - } - } - - /** - * Does the slot have a caption - */ - public boolean hasCaption() { - return caption != null; - } - - /** - * Get the slots caption element - */ - public Element getCaptionElement() { - return caption; - } - - /** - * Set if the slot has a relative width - * - * @param relativeWidth - * True if slot uses relative width, false if the slot has a - * static width - */ - private boolean relativeWidth = false; - - public void setRelativeWidth(boolean relativeWidth) { - this.relativeWidth = relativeWidth; - updateRelativeSize(relativeWidth, "width"); - } - - /** - * Set if the slot has a relative height - * - * @param relativeHeight - * Trie if the slot uses a relative height, false if the slot - * has a static height - */ - private boolean relativeHeight = false; - - public void setRelativeHeight(boolean relativeHeight) { - this.relativeHeight = relativeHeight; - updateRelativeSize(relativeHeight, "height"); - } - - /** - * Updates the captions size if the slot is relative - * - * @param isRelativeSize - * Is the slot relatived sized - * @param direction - * The directorion of the caption - */ - private void updateRelativeSize(boolean isRelativeSize, String direction) { - if (isRelativeSize && hasCaption()) { - captionWrap.getStyle().setProperty( - direction, - getWidget().getElement().getStyle() - .getProperty(direction)); - captionWrap.addClassName("v-has-" + direction); - } else if (hasCaption()) { - if (direction.equals("height")) { - captionWrap.getStyle().clearHeight(); - } else { - captionWrap.getStyle().clearWidth(); - } - captionWrap.removeClassName("v-has-" + direction); - captionWrap.getStyle().clearPaddingTop(); - captionWrap.getStyle().clearPaddingRight(); - captionWrap.getStyle().clearPaddingBottom(); - captionWrap.getStyle().clearPaddingLeft(); - caption.getStyle().clearMarginTop(); - caption.getStyle().clearMarginRight(); - caption.getStyle().clearMarginBottom(); - caption.getStyle().clearMarginLeft(); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt - * .user.client.Event) - */ - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (DOM.eventGetType(event) == Event.ONLOAD - && icon.getElement() == DOM.eventGetTarget(event)) { - if (getLayoutManager() != null) { - getLayoutManager().layoutLater(); - } else { - updateCaptionOffset(caption); - } - } - } - - /* - * (non-Javadoc) - * - * @see com.google.gwt.user.client.ui.SimplePanel#getContainerElement() - */ - @Override - protected Element getContainerElement() { - if (captionWrap == null) { - return getElement(); - } else { - return captionWrap; - } - } - - /* - * (non-Javadoc) - * - * @see com.google.gwt.user.client.ui.Widget#onDetach() - */ - @Override - protected void onDetach() { - if (spacer != null) { - spacer.removeFromParent(); - } - super.onDetach(); - } - - /* - * (non-Javadoc) - * - * @see com.google.gwt.user.client.ui.Widget#onAttach() - */ - @Override - protected void onAttach() { - super.onAttach(); - if (spacer != null) { - getElement().getParentElement().insertBefore(spacer, - getElement()); - } - } - } - - /** - * The icon for each widget. Located in the caption of the slot. - */ - public static class Icon extends UIObject { - - public static final String CLASSNAME = "v-icon"; - - private String myUrl; - - /** - * Constructor - */ - public Icon() { - setElement(DOM.createImg()); - DOM.setElementProperty(getElement(), "alt", ""); - setStyleName(CLASSNAME); - } - - /** - * Set the URL where the icon is located - * - * @param url - * A fully qualified URL - */ - public void setUri(String url) { - if (!url.equals(myUrl)) { - /* - * Start sinking onload events, widgets responsibility to react. - * We must do this BEFORE we set src as IE fires the event - * immediately if the image is found in cache (#2592). - */ - sinkEvents(Event.ONLOAD); - - DOM.setElementProperty(getElement(), "src", url); - myUrl = url; - } - } - } - - /** - * Set the layout manager for the layout - * - * @param manager - * The layout manager to use - */ - public void setLayoutManager(LayoutManager manager) { - layoutManager = manager; - } - - /** - * Get the layout manager used by this layout - * - */ - public LayoutManager getLayoutManager() { - return layoutManager; - } - - /** - * Deducts the caption position by examining the wrapping element. - * <p> - * For internal use only. May be removed or replaced in the future. - * - * @param captionWrap - * The wrapping element - * - * @return The caption position - */ - public CaptionPosition getCaptionPositionFromElement(Element captionWrap) { - RegExp captionPositionRegexp = RegExp.compile("v-caption-on-(\\S+)"); - - // Get caption position from the classname - MatchResult matcher = captionPositionRegexp.exec(captionWrap - .getClassName()); - if (matcher == null || matcher.getGroupCount() < 2) { - return CaptionPosition.TOP; - } - String captionClass = matcher.getGroup(1); - CaptionPosition captionPosition = CaptionPosition.valueOf( - CaptionPosition.class, captionClass.toUpperCase()); - return captionPosition; - } - - /** - * Update the offset off the caption relative to the slot - * <p> - * For internal use only. May be removed or replaced in the future. - * - * @param caption - * The caption element - */ - public void updateCaptionOffset(Element caption) { - - Element captionWrap = caption.getParentElement().cast(); - - Style captionWrapStyle = captionWrap.getStyle(); - captionWrapStyle.clearPaddingTop(); - captionWrapStyle.clearPaddingRight(); - captionWrapStyle.clearPaddingBottom(); - captionWrapStyle.clearPaddingLeft(); - - Style captionStyle = caption.getStyle(); - captionStyle.clearMarginTop(); - captionStyle.clearMarginRight(); - captionStyle.clearMarginBottom(); - captionStyle.clearMarginLeft(); - - // Get caption position from the classname - CaptionPosition captionPosition = getCaptionPositionFromElement(captionWrap); - - if (captionPosition == CaptionPosition.LEFT - || captionPosition == CaptionPosition.RIGHT) { - int captionWidth; - if (layoutManager != null) { - captionWidth = layoutManager.getOuterWidth(caption) - - layoutManager.getMarginWidth(caption); - } else { - captionWidth = caption.getOffsetWidth(); - } - if (captionWidth > 0) { - if (captionPosition == CaptionPosition.LEFT) { - captionWrapStyle.setPaddingLeft(captionWidth, Unit.PX); - captionStyle.setMarginLeft(-captionWidth, Unit.PX); - } else { - captionWrapStyle.setPaddingRight(captionWidth, Unit.PX); - captionStyle.setMarginRight(-captionWidth, Unit.PX); - } - } - } - if (captionPosition == CaptionPosition.TOP - || captionPosition == CaptionPosition.BOTTOM) { - int captionHeight; - if (layoutManager != null) { - captionHeight = layoutManager.getOuterHeight(caption) - - layoutManager.getMarginHeight(caption); - } else { - captionHeight = caption.getOffsetHeight(); - } - if (captionHeight > 0) { - if (captionPosition == CaptionPosition.TOP) { - captionWrapStyle.setPaddingTop(captionHeight, Unit.PX); - captionStyle.setMarginTop(-captionHeight, Unit.PX); - } else { - captionWrapStyle.setPaddingBottom(captionHeight, Unit.PX); - captionStyle.setMarginBottom(-captionHeight, Unit.PX); - } - } - } - } - - /** - * Set the margin of the layout - * - * @param marginInfo - * The margin information - */ - public void setMargin(MarginInfo marginInfo) { - if (marginInfo != null) { - setStyleName("v-margin-top", marginInfo.hasTop()); - setStyleName("v-margin-right", marginInfo.hasRight()); - setStyleName("v-margin-bottom", marginInfo.hasBottom()); - setStyleName("v-margin-left", marginInfo.hasLeft()); - } - } - - /** - * Turn on or off spacing in the layout - * - * @param spacing - * True if spacing should be used, false if not - */ - public void setSpacing(boolean spacing) { - this.spacing = spacing; - for (Slot slot : widgetToSlot.values()) { - if (getWidgetIndex(slot) > 0) { - slot.setSpacing(spacing); - } else { - slot.setSpacing(false); - } - } - } - - /** - * Triggers a recalculation of the expand width and heights - */ - private void recalculateExpands() { - double total = 0; - for (Slot slot : widgetToSlot.values()) { - if (slot.getExpandRatio() > -1) { - total += slot.getExpandRatio(); - } else { - if (vertical) { - slot.getElement().getStyle().clearHeight(); - } else { - slot.getElement().getStyle().clearWidth(); - } - } - } - for (Slot slot : widgetToSlot.values()) { - if (slot.getExpandRatio() > -1) { - if (vertical) { - slot.setHeight((100 * (slot.getExpandRatio() / total)) - + "%"); - if (slot.relativeHeight) { - Util.notifyParentOfSizeChange(this, true); - } - } else { - slot.setWidth((100 * (slot.getExpandRatio() / total)) + "%"); - if (slot.relativeWidth) { - Util.notifyParentOfSizeChange(this, true); - } - } - } - } - } - - /** - * Removes elements used to expand a slot. - * <p> - * For internal use only. May be removed or replaced in the future. - */ - public void clearExpand() { - if (expandWrapper != null) { - for (; expandWrapper.getChildCount() > 0;) { - Element el = expandWrapper.getChild(0).cast(); - getElement().appendChild(el); - if (vertical) { - el.getStyle().clearHeight(); - el.getStyle().clearMarginTop(); - } else { - el.getStyle().clearWidth(); - el.getStyle().clearMarginLeft(); - } - } - expandWrapper.removeFromParent(); - expandWrapper = null; - } - } - - /** - * Adds elements used to expand a slot - */ - public void updateExpand() { - boolean isExpanding = false; - for (Widget slot : getChildren()) { - if (((Slot) slot).getExpandRatio() > -1) { - isExpanding = true; - } else { - if (vertical) { - slot.getElement().getStyle().clearHeight(); - } else { - slot.getElement().getStyle().clearWidth(); - } - } - slot.getElement().getStyle().clearMarginLeft(); - slot.getElement().getStyle().clearMarginTop(); - } - - if (isExpanding) { - if (expandWrapper == null) { - expandWrapper = DOM.createDiv(); - expandWrapper.setClassName("v-expand"); - for (; getElement().getChildCount() > 0;) { - Node el = getElement().getChild(0); - expandWrapper.appendChild(el); - } - getElement().appendChild(expandWrapper); - } - - int totalSize = 0; - for (Widget w : getChildren()) { - Slot slot = (Slot) w; - if (slot.getExpandRatio() == -1) { - - if (layoutManager != null) { - // TODO check caption position - if (vertical) { - int size = layoutManager.getOuterHeight(slot - .getWidget().getElement()) - - layoutManager.getMarginHeight(slot - .getWidget().getElement()); - if (slot.hasCaption()) { - size += layoutManager.getOuterHeight(slot - .getCaptionElement()) - - layoutManager.getMarginHeight(slot - .getCaptionElement()); - } - if (size > 0) { - totalSize += size; - } - } else { - int max = -1; - max = layoutManager.getOuterWidth(slot.getWidget() - .getElement()) - - layoutManager.getMarginWidth(slot - .getWidget().getElement()); - if (slot.hasCaption()) { - int max2 = layoutManager.getOuterWidth(slot - .getCaptionElement()) - - layoutManager.getMarginWidth(slot - .getCaptionElement()); - max = Math.max(max, max2); - } - if (max > 0) { - totalSize += max; - } - } - } else { - totalSize += vertical ? slot.getOffsetHeight() : slot - .getOffsetWidth(); - } - } - // TODO fails in Opera, always returns 0 - int spacingSize = vertical ? slot.getVerticalSpacing() : slot - .getHorizontalSpacing(); - if (spacingSize > 0) { - totalSize += spacingSize; - } - } - - // When we set the margin to the first child, we don't need - // overflow:hidden in the layout root element, since the wrapper - // would otherwise be placed outside of the layout root element - // and block events on elements below it. - if (vertical) { - expandWrapper.getStyle().setPaddingTop(totalSize, Unit.PX); - expandWrapper.getFirstChildElement().getStyle() - .setMarginTop(-totalSize, Unit.PX); - } else { - expandWrapper.getStyle().setPaddingLeft(totalSize, Unit.PX); - expandWrapper.getFirstChildElement().getStyle() - .setMarginLeft(-totalSize, Unit.PX); - } - - recalculateExpands(); - } - } - - /** - * Perform a recalculation of the layout height - */ - public void recalculateLayoutHeight() { - // Only needed if a horizontal layout is undefined high, and contains - // relative height children or vertical alignments - if (vertical || definedHeight) { - return; - } - - boolean hasRelativeHeightChildren = false; - boolean hasVAlign = false; - - for (Widget slot : getChildren()) { - Widget widget = ((Slot) slot).getWidget(); - String h = widget.getElement().getStyle().getHeight(); - if (h != null && h.indexOf("%") > -1) { - hasRelativeHeightChildren = true; - } - AlignmentInfo a = ((Slot) slot).getAlignment(); - if (a != null && (a.isVerticalCenter() || a.isBottom())) { - hasVAlign = true; - } - } - - if (hasRelativeHeightChildren || hasVAlign) { - int newHeight; - if (layoutManager != null) { - newHeight = layoutManager.getOuterHeight(getElement()) - - layoutManager.getMarginHeight(getElement()); - } else { - newHeight = getElement().getOffsetHeight(); - } - VOrderedLayout.this.getElement().getStyle() - .setHeight(newHeight, Unit.PX); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void setHeight(String height) { - super.setHeight(height); - definedHeight = (height != null && !"".equals(height)); - } - - /** - * Sets the slots style names. The style names will be prefixed with the - * v-slot prefix. - * - * @param stylenames - * The style names of the slot. - */ - public void setSlotStyleNames(Widget widget, String... stylenames) { - Slot slot = getSlot(widget); - if (slot == null) { - throw new IllegalArgumentException( - "A slot for the widget could not be found. Has the widget been added to the layout?"); - } - slot.setStyleNames(stylenames); - } - -} diff --git a/client/src/com/vaadin/client/ui/VVerticalLayout.java b/client/src/com/vaadin/client/ui/VVerticalLayout.java index 1a3ce332f5..2a81e61d9a 100644 --- a/client/src/com/vaadin/client/ui/VVerticalLayout.java +++ b/client/src/com/vaadin/client/ui/VVerticalLayout.java @@ -16,11 +16,12 @@ package com.vaadin.client.ui; import com.vaadin.client.StyleConstants; +import com.vaadin.client.ui.orderedlayout.VAbstractOrderedLayout; /** * Represents a layout where the children is ordered vertically */ -public class VVerticalLayout extends VOrderedLayout { +public class VVerticalLayout extends VAbstractOrderedLayout { public static final String CLASSNAME = "v-verticallayout"; diff --git a/client/src/com/vaadin/client/ui/colorpicker/AbstractColorPickerConnector.java b/client/src/com/vaadin/client/ui/colorpicker/AbstractColorPickerConnector.java new file mode 100644 index 0000000000..27261b3812 --- /dev/null +++ b/client/src/com/vaadin/client/ui/colorpicker/AbstractColorPickerConnector.java @@ -0,0 +1,86 @@ +package com.vaadin.client.ui.colorpicker; + +import java.util.Set; + +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.HasClickHandlers; +import com.vaadin.client.communication.StateChangeEvent; +import com.vaadin.client.ui.AbstractComponentConnector; +import com.vaadin.shared.ui.colorpicker.ColorPickerState; + +/** + * An abstract class that defines default implementation for a color picker + * connector. + * + * @since 7.0.0 + */ +public abstract class AbstractColorPickerConnector extends + AbstractComponentConnector implements ClickHandler { + + @Override + public ColorPickerState getState() { + return (ColorPickerState) super.getState(); + } + + @Override + public boolean delegateCaptionHandling() { + return false; + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + // NOTE: this method is called after @DelegateToWidget + super.onStateChanged(stateChangeEvent); + Set<String> changedProperties = stateChangeEvent.getChangedProperties(); + if (changedProperties.contains("color")) { + refreshColor(); + + if (getState().showDefaultCaption + && (getState().caption == null || "" + .equals(getState().caption))) { + + setCaption(getState().color); + } + } + if (changedProperties.contains("caption") + || changedProperties.contains("htmlContentAllowed") + || changedProperties.contains("showDefaultCaption")) { + + setCaption(getCaption()); + } + } + + @Override + public void init() { + super.init(); + if (getWidget() instanceof HasClickHandlers) { + ((HasClickHandlers) getWidget()).addClickHandler(this); + } + } + + /** + * Get caption for the color picker widget. + * + * @return + */ + protected String getCaption() { + if (getState().showDefaultCaption + && (getState().caption == null || "".equals(getState().caption))) { + return getState().color; + } + return getState().caption; + } + + /** + * Set caption of the color picker widget. + * + * @param caption + */ + protected abstract void setCaption(String caption); + + /** + * Update the widget to show the currently selected color. + */ + protected abstract void refreshColor(); + +} diff --git a/client/src/com/vaadin/client/ui/colorpicker/ColorPickerAreaConnector.java b/client/src/com/vaadin/client/ui/colorpicker/ColorPickerAreaConnector.java new file mode 100644 index 0000000000..12bc23966f --- /dev/null +++ b/client/src/com/vaadin/client/ui/colorpicker/ColorPickerAreaConnector.java @@ -0,0 +1,53 @@ +package com.vaadin.client.ui.colorpicker; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.communication.RpcProxy; +import com.vaadin.client.ui.VColorPickerArea; +import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.ui.colorpicker.ColorPickerServerRpc; + +/** + * A class that defines an implementation for a color picker connector. Connects + * the server side {@link com.vaadin.ui.ColorPickerArea} with the client side + * counterpart {@link VColorPickerArea} + * + * @since 7.0.0 + */ +@Connect(com.vaadin.ui.ColorPickerArea.class) +public class ColorPickerAreaConnector extends AbstractColorPickerConnector { + + private ColorPickerServerRpc rpc = RpcProxy.create( + ColorPickerServerRpc.class, this); + + @Override + protected Widget createWidget() { + return GWT.create(VColorPickerArea.class); + } + + @Override + public VColorPickerArea getWidget() { + return (VColorPickerArea) super.getWidget(); + } + + @Override + public void onClick(ClickEvent event) { + rpc.openPopup(getWidget().isOpen()); + } + + @Override + protected void setCaption(String caption) { + if (getState().htmlContentAllowed) { + getWidget().setHTML(caption); + } else { + getWidget().setText(caption); + } + } + + @Override + protected void refreshColor() { + getWidget().refreshColor(); + } + +} diff --git a/client/src/com/vaadin/client/ui/colorpicker/ColorPickerConnector.java b/client/src/com/vaadin/client/ui/colorpicker/ColorPickerConnector.java new file mode 100644 index 0000000000..7329bffa09 --- /dev/null +++ b/client/src/com/vaadin/client/ui/colorpicker/ColorPickerConnector.java @@ -0,0 +1,52 @@ +package com.vaadin.client.ui.colorpicker; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.communication.RpcProxy; +import com.vaadin.client.ui.VColorPicker; +import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.ui.colorpicker.ColorPickerServerRpc; + +/** + * A class that defines default implementation for a color picker connector. + * Connects the server side {@link com.vaadin.ui.ColorPicker} with the client + * side counterpart {@link VColorPicker} + * + * @since 7.0.0 + */ +@Connect(com.vaadin.ui.ColorPicker.class) +public class ColorPickerConnector extends AbstractColorPickerConnector { + + private ColorPickerServerRpc rpc = RpcProxy.create( + ColorPickerServerRpc.class, this); + + @Override + protected Widget createWidget() { + return GWT.create(VColorPicker.class); + } + + @Override + public VColorPicker getWidget() { + return (VColorPicker) super.getWidget(); + } + + @Override + public void onClick(ClickEvent event) { + rpc.openPopup(getWidget().isOpen()); + } + + @Override + protected void setCaption(String caption) { + if (getState().htmlContentAllowed) { + getWidget().setHtml(caption); + } else { + getWidget().setText(caption); + } + } + + @Override + protected void refreshColor() { + getWidget().refreshColor(); + } +} diff --git a/client/src/com/vaadin/client/ui/colorpicker/ColorPickerGradientConnector.java b/client/src/com/vaadin/client/ui/colorpicker/ColorPickerGradientConnector.java new file mode 100644 index 0000000000..9a9dd09999 --- /dev/null +++ b/client/src/com/vaadin/client/ui/colorpicker/ColorPickerGradientConnector.java @@ -0,0 +1,71 @@ +package com.vaadin.client.ui.colorpicker; + +import java.util.Set; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.MouseUpEvent; +import com.google.gwt.event.dom.client.MouseUpHandler; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.communication.RpcProxy; +import com.vaadin.client.communication.StateChangeEvent; +import com.vaadin.client.ui.AbstractComponentConnector; +import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.ui.colorpicker.ColorPickerGradientServerRpc; +import com.vaadin.shared.ui.colorpicker.ColorPickerGradientState; + +/** + * A class that defines the default implementation for a color picker gradient + * connector. Connects the server side + * {@link com.vaadin.ui.components.colorpicker.ColorPickerGradient} with the + * client side counterpart {@link VColorPickerGradient} + * + * @since 7.0.0 + */ +@Connect(com.vaadin.ui.components.colorpicker.ColorPickerGradient.class) +public class ColorPickerGradientConnector extends AbstractComponentConnector + implements MouseUpHandler { + + private ColorPickerGradientServerRpc rpc = RpcProxy.create( + ColorPickerGradientServerRpc.class, this); + + @Override + protected Widget createWidget() { + return GWT.create(VColorPickerGradient.class); + } + + @Override + public VColorPickerGradient getWidget() { + return (VColorPickerGradient) super.getWidget(); + } + + @Override + public ColorPickerGradientState getState() { + return (ColorPickerGradientState) super.getState(); + } + + @Override + public void onMouseUp(MouseUpEvent event) { + rpc.select(getWidget().getCursorX(), getWidget().getCursorY()); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + Set<String> changedProperties = stateChangeEvent.getChangedProperties(); + if (changedProperties.contains("cursorX") + || changedProperties.contains("cursorY")) { + + getWidget().setCursor(getState().cursorX, getState().cursorY); + } + if (changedProperties.contains("bgColor")) { + getWidget().setBGColor(getState().bgColor); + } + } + + @Override + protected void init() { + super.init(); + getWidget().addMouseUpHandler(this); + } + +}
\ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/colorpicker/ColorPickerGridConnector.java b/client/src/com/vaadin/client/ui/colorpicker/ColorPickerGridConnector.java new file mode 100644 index 0000000000..dbce0dd925 --- /dev/null +++ b/client/src/com/vaadin/client/ui/colorpicker/ColorPickerGridConnector.java @@ -0,0 +1,80 @@ +package com.vaadin.client.ui.colorpicker; + +import java.util.Set; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.communication.RpcProxy; +import com.vaadin.client.communication.StateChangeEvent; +import com.vaadin.client.ui.AbstractComponentConnector; +import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.ui.colorpicker.ColorPickerGridServerRpc; +import com.vaadin.shared.ui.colorpicker.ColorPickerGridState; + +/** + * A class that defines the default implementation for a color picker grid + * connector. Connects the server side + * {@link com.vaadin.ui.components.colorpicker.ColorPickerGrid} with the client + * side counterpart {@link VColorPickerGrid} + * + * @since 7.0.0 + */ +@Connect(com.vaadin.ui.components.colorpicker.ColorPickerGrid.class) +public class ColorPickerGridConnector extends AbstractComponentConnector + implements ClickHandler { + + private ColorPickerGridServerRpc rpc = RpcProxy.create( + ColorPickerGridServerRpc.class, this); + + @Override + protected Widget createWidget() { + return GWT.create(VColorPickerGrid.class); + } + + @Override + public VColorPickerGrid getWidget() { + return (VColorPickerGrid) super.getWidget(); + } + + @Override + public ColorPickerGridState getState() { + return (ColorPickerGridState) super.getState(); + } + + @Override + public void onClick(ClickEvent event) { + rpc.select(getWidget().getSelectedX(), getWidget().getSelectedY()); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + Set<String> changedProperties = stateChangeEvent.getChangedProperties(); + if (changedProperties.contains("rowCount") + || changedProperties.contains("columnCount") + || changedProperties.contains("updateGrid")) { + + getWidget().updateGrid(getState().rowCount, getState().columnCount); + } + if (changedProperties.contains("changedX") + || changedProperties.contains("changedY") + || changedProperties.contains("changedColor") + || changedProperties.contains("updateColor")) { + + getWidget().updateColor(getState().changedColor, + getState().changedX, getState().changedY); + + if (!getWidget().isGridLoaded()) { + rpc.refresh(); + } + } + } + + @Override + protected void init() { + super.init(); + getWidget().addClickHandler(this); + } +} diff --git a/client/src/com/vaadin/client/ui/colorpicker/VColorPickerGradient.java b/client/src/com/vaadin/client/ui/colorpicker/VColorPickerGradient.java new file mode 100644 index 0000000000..6defc57996 --- /dev/null +++ b/client/src/com/vaadin/client/ui/colorpicker/VColorPickerGradient.java @@ -0,0 +1,176 @@ +package com.vaadin.client.ui.colorpicker; + +import com.google.gwt.event.dom.client.MouseDownEvent; +import com.google.gwt.event.dom.client.MouseDownHandler; +import com.google.gwt.event.dom.client.MouseMoveEvent; +import com.google.gwt.event.dom.client.MouseMoveHandler; +import com.google.gwt.event.dom.client.MouseUpEvent; +import com.google.gwt.event.dom.client.MouseUpHandler; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.AbsolutePanel; +import com.google.gwt.user.client.ui.FocusPanel; +import com.google.gwt.user.client.ui.HTML; + +/** + * Client side implementation for ColorPickerGradient. + * + * @since 7.0.0 + * + */ +public class VColorPickerGradient extends FocusPanel implements + MouseDownHandler, MouseUpHandler, MouseMoveHandler { + + /** Set the CSS class name to allow styling. */ + public static final String CLASSNAME = "v-colorpicker-gradient"; + public static final String CLASSNAME_BACKGROUND = CLASSNAME + "-background"; + public static final String CLASSNAME_FOREGROUND = CLASSNAME + "-foreground"; + public static final String CLASSNAME_LOWERBOX = CLASSNAME + "-lowerbox"; + public static final String CLASSNAME_HIGHERBOX = CLASSNAME + "-higherbox"; + public static final String CLASSNAME_CONTAINER = CLASSNAME + "-container"; + public static final String CLASSNAME_CLICKLAYER = CLASSNAME + "-clicklayer"; + + private final HTML background; + private final HTML foreground; + private final HTML lowercross; + private final HTML highercross; + private final HTML clicklayer; + private final AbsolutePanel container; + + private boolean mouseIsDown = false; + + private int cursorX; + private int cursorY; + + /** + * Instantiates the client side component for a color picker gradient. + */ + public VColorPickerGradient() { + super(); + + setStyleName(CLASSNAME); + + int width = 220; + int height = 220; + + background = new HTML(); + background.setStyleName(CLASSNAME_BACKGROUND); + background.setPixelSize(width, height); + + foreground = new HTML(); + foreground.setStyleName(CLASSNAME_FOREGROUND); + foreground.setPixelSize(width, height); + + clicklayer = new HTML(); + clicklayer.setStyleName(CLASSNAME_CLICKLAYER); + clicklayer.setPixelSize(width, height); + clicklayer.addMouseDownHandler(this); + clicklayer.addMouseUpHandler(this); + clicklayer.addMouseMoveHandler(this); + + lowercross = new HTML(); + lowercross.setPixelSize(width / 2, height / 2); + lowercross.setStyleName(CLASSNAME_LOWERBOX); + + highercross = new HTML(); + highercross.setPixelSize(width / 2, height / 2); + highercross.setStyleName(CLASSNAME_HIGHERBOX); + + container = new AbsolutePanel(); + container.setStyleName(CLASSNAME_CONTAINER); + container.setPixelSize(width, height); + container.add(background, 0, 0); + container.add(foreground, 0, 0); + container.add(lowercross, 0, height / 2); + container.add(highercross, width / 2, 0); + container.add(clicklayer, 0, 0); + + add(container); + } + + /** + * Returns the latest x-coordinate for pressed-down mouse cursor. + */ + protected int getCursorX() { + return cursorX; + } + + /** + * Returns the latest y-coordinate for pressed-down mouse cursor. + */ + protected int getCursorY() { + return cursorY; + } + + /** + * Sets the given css color as the background. + * + * @param bgColor + */ + protected void setBGColor(String bgColor) { + background.getElement().getStyle().setProperty("background", bgColor); + } + + @Override + public void onMouseDown(MouseDownEvent event) { + event.preventDefault(); + + mouseIsDown = true; + setCursor(event.getX(), event.getY()); + } + + @Override + public void onMouseUp(MouseUpEvent event) { + event.preventDefault(); + mouseIsDown = false; + setCursor(event.getX(), event.getY()); + + cursorX = event.getX(); + cursorY = event.getY(); + } + + @Override + public void onMouseMove(MouseMoveEvent event) { + event.preventDefault(); + + if (mouseIsDown) { + setCursor(event.getX(), event.getY()); + } + } + + /** + * Sets the latest coordinates for pressed-down mouse cursor and updates the + * cross elements. + * + * @param x + * @param y + */ + public void setCursor(int x, int y) { + cursorX = x; + cursorY = y; + if (x >= 0) { + DOM.setStyleAttribute(lowercross.getElement(), "width", + String.valueOf(x) + "px"); + } + if (y >= 0) { + DOM.setStyleAttribute(lowercross.getElement(), "top", + String.valueOf(y) + "px"); + } + if (y >= 0) { + DOM.setStyleAttribute(lowercross.getElement(), "height", + String.valueOf((background.getOffsetHeight() - y)) + "px"); + } + + if (x >= 0) { + DOM.setStyleAttribute(highercross.getElement(), "width", + String.valueOf((background.getOffsetWidth() - x)) + "px"); + } + if (x >= 0) { + DOM.setStyleAttribute(highercross.getElement(), "left", + String.valueOf(x) + "px"); + } + if (y >= 0) { + DOM.setStyleAttribute(highercross.getElement(), "height", + String.valueOf((y)) + "px"); + } + } +} diff --git a/client/src/com/vaadin/client/ui/colorpicker/VColorPickerGrid.java b/client/src/com/vaadin/client/ui/colorpicker/VColorPickerGrid.java new file mode 100644 index 0000000000..1af65733aa --- /dev/null +++ b/client/src/com/vaadin/client/ui/colorpicker/VColorPickerGrid.java @@ -0,0 +1,132 @@ +package com.vaadin.client.ui.colorpicker; + +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.HasClickHandlers; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.AbsolutePanel; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.HTMLTable.Cell; + +/** + * Client side implementation for ColorPickerGrid. + * + * @since 7.0.0 + * + */ +public class VColorPickerGrid extends AbsolutePanel implements ClickHandler, + HasClickHandlers { + + private int rows = 1; + private int columns = 1; + + private Grid grid; + + private boolean gridLoaded = false; + + private int selectedX; + private int selectedY; + + /** + * Instantiates the client side component for a color picker grid. + */ + public VColorPickerGrid() { + super(); + + this.add(createGrid(), 0, 0); + } + + /** + * Creates a grid according to the current row and column count information. + * + * @return grid + */ + private Grid createGrid() { + grid = new Grid(rows, columns); + grid.setWidth("100%"); + grid.setHeight("100%"); + grid.addClickHandler(this); + return grid; + } + + /** + * Updates the row and column count and creates a new grid based on them. + * The new grid replaces the old grid if one existed. + * + * @param rowCount + * @param columnCount + */ + protected void updateGrid(int rowCount, int columnCount) { + rows = rowCount; + columns = columnCount; + this.remove(grid); + this.add(createGrid(), 0, 0); + } + + /** + * Updates the changed colors within the grid based on the given x- and + * y-coordinates. Nothing happens if any of the parameters is null or the + * parameter lengths don't match. + * + * @param changedColor + * @param changedX + * @param changedY + */ + protected void updateColor(String[] changedColor, String[] changedX, + String[] changedY) { + if (changedColor != null && changedX != null && changedY != null) { + if (changedColor.length == changedX.length + && changedX.length == changedY.length) { + for (int c = 0; c < changedColor.length; c++) { + Element element = grid.getCellFormatter().getElement( + Integer.parseInt(changedX[c]), + Integer.parseInt(changedY[c])); + element.getStyle().setProperty("background", + changedColor[c]); + } + } + + gridLoaded = true; + } + } + + /** + * Returns currently selected x-coordinate of the grid. + */ + protected int getSelectedX() { + return selectedX; + } + + /** + * Returns currently selected y-coordinate of the grid. + */ + protected int getSelectedY() { + return selectedY; + } + + /** + * Returns true if the colors have been successfully updated at least once, + * false otherwise. + */ + protected boolean isGridLoaded() { + return gridLoaded; + } + + @Override + public void onClick(ClickEvent event) { + Cell cell = grid.getCellForEvent(event); + if (cell == null) { + return; + } + + selectedY = cell.getRowIndex(); + selectedX = cell.getCellIndex(); + } + + @Override + public HandlerRegistration addClickHandler(ClickHandler handler) { + return addDomHandler(handler, ClickEvent.getType()); + } + +} diff --git a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java index 65736397cb..e062d37dd6 100644 --- a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java +++ b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java @@ -29,9 +29,6 @@ import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler; import com.vaadin.client.ui.AbstractFieldConnector; import com.vaadin.client.ui.AbstractLayoutConnector; import com.vaadin.client.ui.LayoutClickEventHandler; -import com.vaadin.client.ui.VOrderedLayout; -import com.vaadin.client.ui.VOrderedLayout.CaptionPosition; -import com.vaadin.client.ui.VOrderedLayout.Slot; import com.vaadin.client.ui.layout.ElementResizeEvent; import com.vaadin.client.ui.layout.ElementResizeListener; import com.vaadin.shared.AbstractFieldState; @@ -199,8 +196,8 @@ public abstract class AbstractOrderedLayoutConnector extends * @see com.vaadin.client.ui.AbstractComponentConnector#getWidget() */ @Override - public VOrderedLayout getWidget() { - return (VOrderedLayout) super.getWidget(); + public VAbstractOrderedLayout getWidget() { + return (VAbstractOrderedLayout) super.getWidget(); } /** @@ -300,7 +297,7 @@ public abstract class AbstractOrderedLayoutConnector extends List<ComponentConnector> previousChildren = event.getOldChildren(); int currentIndex = 0; - VOrderedLayout layout = getWidget(); + VAbstractOrderedLayout layout = getWidget(); layout.setSpacing(getState().spacing); diff --git a/client/src/com/vaadin/client/ui/orderedlayout/CaptionPosition.java b/client/src/com/vaadin/client/ui/orderedlayout/CaptionPosition.java new file mode 100644 index 0000000000..612d00b574 --- /dev/null +++ b/client/src/com/vaadin/client/ui/orderedlayout/CaptionPosition.java @@ -0,0 +1,24 @@ +/* + * Copyright 2012 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.client.ui.orderedlayout; + +/** + * Defines where the caption should be placed + */ +public enum CaptionPosition { + TOP, RIGHT, BOTTOM, LEFT +}
\ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/orderedlayout/Slot.java b/client/src/com/vaadin/client/ui/orderedlayout/Slot.java new file mode 100644 index 0000000000..094a7f1f0a --- /dev/null +++ b/client/src/com/vaadin/client/ui/orderedlayout/Slot.java @@ -0,0 +1,658 @@ +/* + * Copyright 2012 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.client.ui.orderedlayout; + +import java.util.List; + +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.UIObject; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.LayoutManager; +import com.vaadin.client.StyleConstants; +import com.vaadin.client.ui.layout.ElementResizeListener; +import com.vaadin.shared.ui.AlignmentInfo; + +/** + * Represents a slot which contains the actual widget in the layout. + */ +public final class Slot extends SimplePanel { + /** + * The icon for each widget. Located in the caption of the slot. + */ + private static class Icon extends UIObject { + + public static final String CLASSNAME = "v-icon"; + + private String myUrl; + + /** + * Constructor + */ + public Icon() { + setElement(DOM.createImg()); + DOM.setElementProperty(getElement(), "alt", ""); + setStyleName(CLASSNAME); + } + + /** + * Set the URL where the icon is located + * + * @param url + * A fully qualified URL + */ + public void setUri(String url) { + if (!url.equals(myUrl)) { + /* + * Start sinking onload events, widgets responsibility to react. + * We must do this BEFORE we set src as IE fires the event + * immediately if the image is found in cache (#2592). + */ + sinkEvents(Event.ONLOAD); + + DOM.setElementProperty(getElement(), "src", url); + myUrl = url; + } + } + } + + private static final String ALIGN_CLASS_PREFIX = "v-align-"; + + private final VAbstractOrderedLayout layout; + + public static final String SLOT_CLASSNAME = "v-slot"; + + private Element spacer; + private Element captionWrap; + private Element caption; + private Element captionText; + private Icon icon; + private Element errorIcon; + private Element requiredIcon; + + private ElementResizeListener captionResizeListener; + + private ElementResizeListener widgetResizeListener; + + private ElementResizeListener spacingResizeListener; + + // Caption is placed after component unless there is some part which + // moves it above. + private CaptionPosition captionPosition = CaptionPosition.RIGHT; + + private AlignmentInfo alignment; + + private double expandRatio = -1; + + /** + * Constructor + * + * @param widget + * The widget to put in the slot + * @param layout + * TODO + * + * @param layoutManager + * The layout manager used by the layout + */ + public Slot(VAbstractOrderedLayout layout, Widget widget) { + this.layout = layout; + setStyleName(SLOT_CLASSNAME); + setWidget(widget); + } + + /* + * (non-Javadoc) + * + * @see com.google.gwt.user.client.ui.SimplePanel#remove(com.google.gwt.user + * .client.ui.Widget) + */ + @Override + public boolean remove(Widget w) { + detachListeners(); + return super.remove(w); + } + + /* + * (non-Javadoc) + * + * @see com.google.gwt.user.client.ui.SimplePanel#setWidget(com.google.gwt + * .user.client.ui.Widget) + */ + @Override + public void setWidget(Widget w) { + detachListeners(); + super.setWidget(w); + attachListeners(); + } + + /** + * Attached resize listeners to the widget, caption and spacing elements + */ + private void attachListeners() { + if (getWidget() != null && layout.getLayoutManager() != null) { + LayoutManager lm = layout.getLayoutManager(); + if (getCaptionElement() != null && captionResizeListener != null) { + lm.addElementResizeListener(getCaptionElement(), + captionResizeListener); + } + if (widgetResizeListener != null) { + lm.addElementResizeListener(getWidget().getElement(), + widgetResizeListener); + } + if (getSpacingElement() != null && spacingResizeListener != null) { + lm.addElementResizeListener(getSpacingElement(), + spacingResizeListener); + } + } + } + + /** + * Detaches resize listeners from the widget, caption and spacing elements + */ + private void detachListeners() { + if (getWidget() != null && layout.getLayoutManager() != null) { + LayoutManager lm = layout.getLayoutManager(); + if (getCaptionElement() != null && captionResizeListener != null) { + lm.removeElementResizeListener(getCaptionElement(), + captionResizeListener); + } + if (widgetResizeListener != null) { + lm.removeElementResizeListener(getWidget().getElement(), + widgetResizeListener); + } + if (getSpacingElement() != null && spacingResizeListener != null) { + lm.removeElementResizeListener(getSpacingElement(), + spacingResizeListener); + } + } + } + + public ElementResizeListener getCaptionResizeListener() { + return captionResizeListener; + } + + public void setCaptionResizeListener( + ElementResizeListener captionResizeListener) { + detachListeners(); + this.captionResizeListener = captionResizeListener; + attachListeners(); + } + + public ElementResizeListener getWidgetResizeListener() { + return widgetResizeListener; + } + + public void setWidgetResizeListener( + ElementResizeListener widgetResizeListener) { + detachListeners(); + this.widgetResizeListener = widgetResizeListener; + attachListeners(); + } + + public ElementResizeListener getSpacingResizeListener() { + return spacingResizeListener; + } + + public void setSpacingResizeListener( + ElementResizeListener spacingResizeListener) { + detachListeners(); + this.spacingResizeListener = spacingResizeListener; + attachListeners(); + } + + /** + * Returns the alignment for the slot + * + */ + public AlignmentInfo getAlignment() { + return alignment; + } + + /** + * Sets the style names for the slot containing the widget + * + * @param stylenames + * The style names for the slot + */ + protected void setStyleNames(String... stylenames) { + setStyleName(SLOT_CLASSNAME); + if (stylenames != null) { + for (String stylename : stylenames) { + addStyleDependentName(stylename); + } + } + + // Ensure alignment style names are correct + setAlignment(alignment); + } + + /** + * Sets how the widget is aligned inside the slot + * + * @param alignment + * The alignment inside the slot + */ + public void setAlignment(AlignmentInfo alignment) { + this.alignment = alignment; + + if (alignment != null && alignment.isHorizontalCenter()) { + addStyleName(ALIGN_CLASS_PREFIX + "center"); + removeStyleName(ALIGN_CLASS_PREFIX + "right"); + } else if (alignment != null && alignment.isRight()) { + addStyleName(ALIGN_CLASS_PREFIX + "right"); + removeStyleName(ALIGN_CLASS_PREFIX + "center"); + } else { + removeStyleName(ALIGN_CLASS_PREFIX + "right"); + removeStyleName(ALIGN_CLASS_PREFIX + "center"); + } + + if (alignment != null && alignment.isVerticalCenter()) { + addStyleName(ALIGN_CLASS_PREFIX + "middle"); + removeStyleName(ALIGN_CLASS_PREFIX + "bottom"); + } else if (alignment != null && alignment.isBottom()) { + addStyleName(ALIGN_CLASS_PREFIX + "bottom"); + removeStyleName(ALIGN_CLASS_PREFIX + "middle"); + } else { + removeStyleName(ALIGN_CLASS_PREFIX + "middle"); + removeStyleName(ALIGN_CLASS_PREFIX + "bottom"); + } + } + + /** + * Set how the slot should be expanded relative to the other slots + * + * @param expandRatio + * The ratio of the space the slot should occupy + * + */ + public void setExpandRatio(double expandRatio) { + this.expandRatio = expandRatio; + } + + /** + * Get the expand ratio for the slot. The expand ratio describes how the + * slot should be resized compared to other slots in the layout + * + * @return + */ + public double getExpandRatio() { + return expandRatio; + } + + /** + * Set the spacing for the slot. The spacing determines if there should be + * empty space around the slot when the slot. + * + * @param spacing + * Should spacing be enabled + */ + public void setSpacing(boolean spacing) { + if (spacing && spacer == null) { + spacer = DOM.createDiv(); + spacer.addClassName("v-spacing"); + + /* + * This has to be done here for the initial render. In other cases + * where the spacer already exists onAttach will handle it. + */ + getElement().getParentElement().insertBefore(spacer, getElement()); + } else if (!spacing && spacer != null) { + spacer.removeFromParent(); + spacer = null; + } + } + + /** + * Get the element which is added to make the spacing + * + * @return + */ + public Element getSpacingElement() { + return spacer; + } + + /** + * Does the slot have spacing + */ + public boolean hasSpacing() { + return getSpacingElement() != null; + } + + /** + * Get the vertical amount in pixels of the spacing + */ + protected int getVerticalSpacing() { + if (spacer == null) { + return 0; + } else if (layout.getLayoutManager() != null) { + return layout.getLayoutManager().getOuterHeight(spacer); + } + return spacer.getOffsetHeight(); + } + + /** + * Get the horizontal amount of pixels of the spacing + * + * @return + */ + protected int getHorizontalSpacing() { + if (spacer == null) { + return 0; + } else if (layout.getLayoutManager() != null) { + return layout.getLayoutManager().getOuterWidth(spacer); + } + return spacer.getOffsetWidth(); + } + + /** + * Set the position of the caption relative to the slot + * + * @param captionPosition + * The position of the caption + */ + public void setCaptionPosition(CaptionPosition captionPosition) { + if (caption == null) { + return; + } + captionWrap.removeClassName("v-caption-on-" + + this.captionPosition.name().toLowerCase()); + + this.captionPosition = captionPosition; + if (captionPosition == CaptionPosition.BOTTOM + || captionPosition == CaptionPosition.RIGHT) { + captionWrap.appendChild(caption); + } else { + captionWrap.insertFirst(caption); + } + + captionWrap.addClassName("v-caption-on-" + + captionPosition.name().toLowerCase()); + } + + /** + * Get the position of the caption relative to the slot + */ + public CaptionPosition getCaptionPosition() { + return captionPosition; + } + + /** + * Set the caption of the slot + * + * @param captionText + * The text of the caption + * @param iconUrl + * The icon URL + * @param styles + * The style names + * @param error + * The error message + * @param showError + * Should the error message be shown + * @param required + * Is the (field) required + * @param enabled + * Is the component enabled + */ + public void setCaption(String captionText, String iconUrl, + List<String> styles, String error, boolean showError, + boolean required, boolean enabled) { + + // TODO place for optimization: check if any of these have changed + // since last time, and only run those changes + + // Caption wrappers + if (captionText != null || iconUrl != null || error != null || required) { + if (caption == null) { + caption = DOM.createDiv(); + captionWrap = DOM.createDiv(); + captionWrap.addClassName(StyleConstants.UI_WIDGET); + captionWrap.addClassName("v-has-caption"); + getElement().appendChild(captionWrap); + captionWrap.appendChild(getWidget().getElement()); + } + } else if (caption != null) { + getElement().appendChild(getWidget().getElement()); + captionWrap.removeFromParent(); + caption = null; + captionWrap = null; + } + + // Caption text + if (captionText != null) { + if (this.captionText == null) { + this.captionText = DOM.createSpan(); + this.captionText.addClassName("v-captiontext"); + caption.appendChild(this.captionText); + } + if (captionText.trim().equals("")) { + this.captionText.setInnerHTML(" "); + } else { + this.captionText.setInnerText(captionText); + } + } else if (this.captionText != null) { + this.captionText.removeFromParent(); + this.captionText = null; + } + + // Icon + if (iconUrl != null) { + if (icon == null) { + icon = new Icon(); + caption.insertFirst(icon.getElement()); + } + icon.setUri(iconUrl); + } else if (icon != null) { + icon.getElement().removeFromParent(); + icon = null; + } + + // Required + if (required) { + if (requiredIcon == null) { + requiredIcon = DOM.createSpan(); + // TODO decide something better (e.g. use CSS to insert the + // character) + requiredIcon.setInnerHTML("*"); + requiredIcon.setClassName("v-required-field-indicator"); + } + caption.appendChild(requiredIcon); + } else if (requiredIcon != null) { + requiredIcon.removeFromParent(); + requiredIcon = null; + } + + // Error + if (error != null && showError) { + if (errorIcon == null) { + errorIcon = DOM.createSpan(); + errorIcon.setClassName("v-errorindicator"); + } + caption.appendChild(errorIcon); + } else if (errorIcon != null) { + errorIcon.removeFromParent(); + errorIcon = null; + } + + if (caption != null) { + // Styles + caption.setClassName("v-caption"); + + if (styles != null) { + for (String style : styles) { + caption.addClassName("v-caption-" + style); + } + } + + if (enabled) { + caption.removeClassName("v-disabled"); + } else { + caption.addClassName("v-disabled"); + } + + // Caption position + if (captionText != null || iconUrl != null) { + setCaptionPosition(CaptionPosition.TOP); + } else { + setCaptionPosition(CaptionPosition.RIGHT); + } + } + } + + /** + * Does the slot have a caption + */ + public boolean hasCaption() { + return caption != null; + } + + /** + * Get the slots caption element + */ + public Element getCaptionElement() { + return caption; + } + + private boolean relativeWidth = false; + + /** + * Set if the slot has a relative width + * + * @param relativeWidth + * True if slot uses relative width, false if the slot has a + * static width + */ + public void setRelativeWidth(boolean relativeWidth) { + this.relativeWidth = relativeWidth; + updateRelativeSize(relativeWidth, "width"); + } + + public boolean hasRelativeWidth() { + return relativeWidth; + } + + private boolean relativeHeight = false; + + /** + * Set if the slot has a relative height + * + * @param relativeHeight + * True if the slot uses a relative height, false if the slot has + * a static height + */ + public void setRelativeHeight(boolean relativeHeight) { + this.relativeHeight = relativeHeight; + updateRelativeSize(relativeHeight, "height"); + } + + public boolean hasRelativeHeight() { + return relativeHeight; + } + + /** + * Updates the captions size if the slot is relative + * + * @param isRelativeSize + * Is the slot relatively sized + * @param direction + * The direction of the caption + */ + private void updateRelativeSize(boolean isRelativeSize, String direction) { + if (isRelativeSize && hasCaption()) { + captionWrap.getStyle().setProperty(direction, + getWidget().getElement().getStyle().getProperty(direction)); + captionWrap.addClassName("v-has-" + direction); + } else if (hasCaption()) { + if (direction.equals("height")) { + captionWrap.getStyle().clearHeight(); + } else { + captionWrap.getStyle().clearWidth(); + } + captionWrap.removeClassName("v-has-" + direction); + captionWrap.getStyle().clearPaddingTop(); + captionWrap.getStyle().clearPaddingRight(); + captionWrap.getStyle().clearPaddingBottom(); + captionWrap.getStyle().clearPaddingLeft(); + caption.getStyle().clearMarginTop(); + caption.getStyle().clearMarginRight(); + caption.getStyle().clearMarginBottom(); + caption.getStyle().clearMarginLeft(); + } + } + + /* + * (non-Javadoc) + * + * @see com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt + * .user.client.Event) + */ + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + if (DOM.eventGetType(event) == Event.ONLOAD + && icon.getElement() == DOM.eventGetTarget(event)) { + if (layout.getLayoutManager() != null) { + layout.getLayoutManager().layoutLater(); + } else { + layout.updateCaptionOffset(caption); + } + } + } + + /* + * (non-Javadoc) + * + * @see com.google.gwt.user.client.ui.SimplePanel#getContainerElement() + */ + @Override + protected Element getContainerElement() { + if (captionWrap == null) { + return getElement(); + } else { + return captionWrap; + } + } + + /* + * (non-Javadoc) + * + * @see com.google.gwt.user.client.ui.Widget#onDetach() + */ + @Override + protected void onDetach() { + if (spacer != null) { + spacer.removeFromParent(); + } + super.onDetach(); + } + + /* + * (non-Javadoc) + * + * @see com.google.gwt.user.client.ui.Widget#onAttach() + */ + @Override + protected void onAttach() { + super.onAttach(); + if (spacer != null) { + getElement().getParentElement().insertBefore(spacer, getElement()); + } + } +}
\ No newline at end of file diff --git a/client/src/com/vaadin/client/ui/orderedlayout/VAbstractOrderedLayout.java b/client/src/com/vaadin/client/ui/orderedlayout/VAbstractOrderedLayout.java new file mode 100644 index 0000000000..00b7092d81 --- /dev/null +++ b/client/src/com/vaadin/client/ui/orderedlayout/VAbstractOrderedLayout.java @@ -0,0 +1,552 @@ +/* + * Copyright 2011 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.client.ui.orderedlayout; + +import java.util.HashMap; +import java.util.Map; + +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.regexp.shared.MatchResult; +import com.google.gwt.regexp.shared.RegExp; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.LayoutManager; +import com.vaadin.client.Util; +import com.vaadin.shared.ui.AlignmentInfo; +import com.vaadin.shared.ui.MarginInfo; + +/** + * Base class for ordered layouts + */ +public class VAbstractOrderedLayout extends FlowPanel { + + protected boolean spacing = false; + + /** For internal use only. May be removed or replaced in the future. */ + public boolean vertical = true; + + protected boolean definedHeight = false; + + private Map<Widget, Slot> widgetToSlot = new HashMap<Widget, Slot>(); + + private Element expandWrapper; + + private LayoutManager layoutManager; + + public VAbstractOrderedLayout(boolean vertical) { + this.vertical = vertical; + } + + /** + * Add or move a slot to another index. + * <p> + * For internal use only. May be removed or replaced in the future. + * <p> + * You should note that the index does not refer to the DOM index if + * spacings are used. If spacings are used then the index will be adjusted + * to include the spacings when inserted. + * <p> + * For instance when using spacing the index converts to DOM index in the + * following way: + * + * <pre> + * index : 0 -> DOM index: 0 + * index : 1 -> DOM index: 1 + * index : 2 -> DOM index: 3 + * index : 3 -> DOM index: 5 + * index : 4 -> DOM index: 7 + * </pre> + * + * When using this method never account for spacings. + * </p> + * + * @param slot + * The slot to move or add + * @param index + * The index where the slot should be placed. + */ + public void addOrMoveSlot(Slot slot, int index) { + if (slot.getParent() == this) { + int currentIndex = getWidgetIndex(slot); + if (index == currentIndex) { + return; + } + } + + insert(slot, index); + + /* + * We need to confirm spacings are correctly applied after each insert. + */ + setSpacing(spacing); + } + + /** + * {@inheritDoc} + */ + @Override + protected void insert(Widget child, Element container, int beforeIndex, + boolean domInsert) { + // Validate index; adjust if the widget is already a child of this + // panel. + beforeIndex = adjustIndex(child, beforeIndex); + + // Detach new child. + child.removeFromParent(); + + // Logical attach. + getChildren().insert(child, beforeIndex); + + // Physical attach. + container = expandWrapper != null ? expandWrapper : getElement(); + if (domInsert) { + if (spacing) { + if (beforeIndex != 0) { + /* + * Since the spacing elements are located at the same DOM + * level as the slots we need to take them into account when + * calculating the slot position. + * + * The spacing elements are always located before the actual + * slot except for the first slot which do not have a + * spacing element like this + * + * |<slot1><spacing2><slot2><spacing3><slot3>...| + */ + beforeIndex = beforeIndex * 2 - 1; + } + } + DOM.insertChild(container, child.getElement(), beforeIndex); + } else { + DOM.appendChild(container, child.getElement()); + } + + // Adopt. + adopt(child); + } + + /** + * Remove a slot from the layout + * + * @param widget + * @return + */ + public void removeWidget(Widget widget) { + Slot slot = widgetToSlot.get(widget); + remove(slot); + widgetToSlot.remove(widget); + } + + /** + * Get the containing slot for a widget. If no slot is found a new slot is + * created and returned. + * + * @param widget + * The widget whose slot you want to get + * + * @return + */ + public Slot getSlot(Widget widget) { + Slot slot = widgetToSlot.get(widget); + if (slot == null) { + slot = new Slot(this, widget); + widgetToSlot.put(widget, slot); + } + return slot; + } + + /** + * Gets a slot based on the widget element. If no slot is found then null is + * returned. + * + * @param widgetElement + * The element of the widget ( Same as getWidget().getElement() ) + * @return + */ + public Slot getSlot(Element widgetElement) { + for (Map.Entry<Widget, Slot> entry : widgetToSlot.entrySet()) { + if (entry.getKey().getElement() == widgetElement) { + return entry.getValue(); + } + } + return null; + } + + /** + * Set the layout manager for the layout + * + * @param manager + * The layout manager to use + */ + public void setLayoutManager(LayoutManager manager) { + layoutManager = manager; + } + + /** + * Get the layout manager used by this layout + * + */ + public LayoutManager getLayoutManager() { + return layoutManager; + } + + /** + * Deducts the caption position by examining the wrapping element. + * <p> + * For internal use only. May be removed or replaced in the future. + * + * @param captionWrap + * The wrapping element + * + * @return The caption position + */ + public CaptionPosition getCaptionPositionFromElement(Element captionWrap) { + RegExp captionPositionRegexp = RegExp.compile("v-caption-on-(\\S+)"); + + // Get caption position from the classname + MatchResult matcher = captionPositionRegexp.exec(captionWrap + .getClassName()); + if (matcher == null || matcher.getGroupCount() < 2) { + return CaptionPosition.TOP; + } + String captionClass = matcher.getGroup(1); + CaptionPosition captionPosition = CaptionPosition.valueOf( + CaptionPosition.class, captionClass.toUpperCase()); + return captionPosition; + } + + /** + * Update the offset off the caption relative to the slot + * <p> + * For internal use only. May be removed or replaced in the future. + * + * @param caption + * The caption element + */ + public void updateCaptionOffset(Element caption) { + + Element captionWrap = caption.getParentElement().cast(); + + Style captionWrapStyle = captionWrap.getStyle(); + captionWrapStyle.clearPaddingTop(); + captionWrapStyle.clearPaddingRight(); + captionWrapStyle.clearPaddingBottom(); + captionWrapStyle.clearPaddingLeft(); + + Style captionStyle = caption.getStyle(); + captionStyle.clearMarginTop(); + captionStyle.clearMarginRight(); + captionStyle.clearMarginBottom(); + captionStyle.clearMarginLeft(); + + // Get caption position from the classname + CaptionPosition captionPosition = getCaptionPositionFromElement(captionWrap); + + if (captionPosition == CaptionPosition.LEFT + || captionPosition == CaptionPosition.RIGHT) { + int captionWidth; + if (layoutManager != null) { + captionWidth = layoutManager.getOuterWidth(caption) + - layoutManager.getMarginWidth(caption); + } else { + captionWidth = caption.getOffsetWidth(); + } + if (captionWidth > 0) { + if (captionPosition == CaptionPosition.LEFT) { + captionWrapStyle.setPaddingLeft(captionWidth, Unit.PX); + captionStyle.setMarginLeft(-captionWidth, Unit.PX); + } else { + captionWrapStyle.setPaddingRight(captionWidth, Unit.PX); + captionStyle.setMarginRight(-captionWidth, Unit.PX); + } + } + } + if (captionPosition == CaptionPosition.TOP + || captionPosition == CaptionPosition.BOTTOM) { + int captionHeight; + if (layoutManager != null) { + captionHeight = layoutManager.getOuterHeight(caption) + - layoutManager.getMarginHeight(caption); + } else { + captionHeight = caption.getOffsetHeight(); + } + if (captionHeight > 0) { + if (captionPosition == CaptionPosition.TOP) { + captionWrapStyle.setPaddingTop(captionHeight, Unit.PX); + captionStyle.setMarginTop(-captionHeight, Unit.PX); + } else { + captionWrapStyle.setPaddingBottom(captionHeight, Unit.PX); + captionStyle.setMarginBottom(-captionHeight, Unit.PX); + } + } + } + } + + /** + * Set the margin of the layout + * + * @param marginInfo + * The margin information + */ + public void setMargin(MarginInfo marginInfo) { + if (marginInfo != null) { + setStyleName("v-margin-top", marginInfo.hasTop()); + setStyleName("v-margin-right", marginInfo.hasRight()); + setStyleName("v-margin-bottom", marginInfo.hasBottom()); + setStyleName("v-margin-left", marginInfo.hasLeft()); + } + } + + /** + * Turn on or off spacing in the layout + * + * @param spacing + * True if spacing should be used, false if not + */ + public void setSpacing(boolean spacing) { + this.spacing = spacing; + for (Slot slot : widgetToSlot.values()) { + if (getWidgetIndex(slot) > 0) { + slot.setSpacing(spacing); + } else { + slot.setSpacing(false); + } + } + } + + /** + * Triggers a recalculation of the expand width and heights + */ + private void recalculateExpands() { + double total = 0; + for (Slot slot : widgetToSlot.values()) { + if (slot.getExpandRatio() > -1) { + total += slot.getExpandRatio(); + } else { + if (vertical) { + slot.getElement().getStyle().clearHeight(); + } else { + slot.getElement().getStyle().clearWidth(); + } + } + } + for (Slot slot : widgetToSlot.values()) { + if (slot.getExpandRatio() > -1) { + if (vertical) { + slot.setHeight((100 * (slot.getExpandRatio() / total)) + + "%"); + if (slot.hasRelativeHeight()) { + Util.notifyParentOfSizeChange(this, true); + } + } else { + slot.setWidth((100 * (slot.getExpandRatio() / total)) + "%"); + if (slot.hasRelativeWidth()) { + Util.notifyParentOfSizeChange(this, true); + } + } + } + } + } + + /** + * Removes elements used to expand a slot. + * <p> + * For internal use only. May be removed or replaced in the future. + */ + public void clearExpand() { + if (expandWrapper != null) { + for (; expandWrapper.getChildCount() > 0;) { + Element el = expandWrapper.getChild(0).cast(); + getElement().appendChild(el); + if (vertical) { + el.getStyle().clearHeight(); + el.getStyle().clearMarginTop(); + } else { + el.getStyle().clearWidth(); + el.getStyle().clearMarginLeft(); + } + } + expandWrapper.removeFromParent(); + expandWrapper = null; + } + } + + /** + * Adds elements used to expand a slot + */ + public void updateExpand() { + boolean isExpanding = false; + for (Widget slot : getChildren()) { + if (((Slot) slot).getExpandRatio() > -1) { + isExpanding = true; + } else { + if (vertical) { + slot.getElement().getStyle().clearHeight(); + } else { + slot.getElement().getStyle().clearWidth(); + } + } + slot.getElement().getStyle().clearMarginLeft(); + slot.getElement().getStyle().clearMarginTop(); + } + + if (isExpanding) { + if (expandWrapper == null) { + expandWrapper = DOM.createDiv(); + expandWrapper.setClassName("v-expand"); + for (; getElement().getChildCount() > 0;) { + Node el = getElement().getChild(0); + expandWrapper.appendChild(el); + } + getElement().appendChild(expandWrapper); + } + + int totalSize = 0; + for (Widget w : getChildren()) { + Slot slot = (Slot) w; + if (slot.getExpandRatio() == -1) { + + if (layoutManager != null) { + // TODO check caption position + if (vertical) { + int size = layoutManager.getOuterHeight(slot + .getWidget().getElement()) + - layoutManager.getMarginHeight(slot + .getWidget().getElement()); + if (slot.hasCaption()) { + size += layoutManager.getOuterHeight(slot + .getCaptionElement()) + - layoutManager.getMarginHeight(slot + .getCaptionElement()); + } + if (size > 0) { + totalSize += size; + } + } else { + int max = -1; + max = layoutManager.getOuterWidth(slot.getWidget() + .getElement()) + - layoutManager.getMarginWidth(slot + .getWidget().getElement()); + if (slot.hasCaption()) { + int max2 = layoutManager.getOuterWidth(slot + .getCaptionElement()) + - layoutManager.getMarginWidth(slot + .getCaptionElement()); + max = Math.max(max, max2); + } + if (max > 0) { + totalSize += max; + } + } + } else { + totalSize += vertical ? slot.getOffsetHeight() : slot + .getOffsetWidth(); + } + } + // TODO fails in Opera, always returns 0 + int spacingSize = vertical ? slot.getVerticalSpacing() : slot + .getHorizontalSpacing(); + if (spacingSize > 0) { + totalSize += spacingSize; + } + } + + // When we set the margin to the first child, we don't need + // overflow:hidden in the layout root element, since the wrapper + // would otherwise be placed outside of the layout root element + // and block events on elements below it. + if (vertical) { + expandWrapper.getStyle().setPaddingTop(totalSize, Unit.PX); + expandWrapper.getFirstChildElement().getStyle() + .setMarginTop(-totalSize, Unit.PX); + } else { + expandWrapper.getStyle().setPaddingLeft(totalSize, Unit.PX); + expandWrapper.getFirstChildElement().getStyle() + .setMarginLeft(-totalSize, Unit.PX); + } + + recalculateExpands(); + } + } + + /** + * Perform a recalculation of the layout height + */ + public void recalculateLayoutHeight() { + // Only needed if a horizontal layout is undefined high, and contains + // relative height children or vertical alignments + if (vertical || definedHeight) { + return; + } + + boolean hasRelativeHeightChildren = false; + boolean hasVAlign = false; + + for (Widget slot : getChildren()) { + Widget widget = ((Slot) slot).getWidget(); + String h = widget.getElement().getStyle().getHeight(); + if (h != null && h.indexOf("%") > -1) { + hasRelativeHeightChildren = true; + } + AlignmentInfo a = ((Slot) slot).getAlignment(); + if (a != null && (a.isVerticalCenter() || a.isBottom())) { + hasVAlign = true; + } + } + + if (hasRelativeHeightChildren || hasVAlign) { + int newHeight; + if (layoutManager != null) { + newHeight = layoutManager.getOuterHeight(getElement()) + - layoutManager.getMarginHeight(getElement()); + } else { + newHeight = getElement().getOffsetHeight(); + } + getElement().getStyle().setHeight(newHeight, Unit.PX); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setHeight(String height) { + super.setHeight(height); + definedHeight = (height != null && !"".equals(height)); + } + + /** + * Sets the slots style names. The style names will be prefixed with the + * v-slot prefix. + * + * @param stylenames + * The style names of the slot. + */ + public void setSlotStyleNames(Widget widget, String... stylenames) { + Slot slot = getSlot(widget); + if (slot == null) { + throw new IllegalArgumentException( + "A slot for the widget could not be found. Has the widget been added to the layout?"); + } + slot.setStyleNames(stylenames); + } + +} diff --git a/server/src/com/vaadin/ui/AbstractColorPicker.java b/server/src/com/vaadin/ui/AbstractColorPicker.java new file mode 100644 index 0000000000..38cbeddcb5 --- /dev/null +++ b/server/src/com/vaadin/ui/AbstractColorPicker.java @@ -0,0 +1,450 @@ +package com.vaadin.ui; + +import java.lang.reflect.Method; + +import com.vaadin.shared.ui.colorpicker.Color; +import com.vaadin.shared.ui.colorpicker.ColorPickerServerRpc; +import com.vaadin.shared.ui.colorpicker.ColorPickerState; +import com.vaadin.ui.Window.CloseEvent; +import com.vaadin.ui.Window.CloseListener; +import com.vaadin.ui.components.colorpicker.ColorChangeEvent; +import com.vaadin.ui.components.colorpicker.ColorChangeListener; +import com.vaadin.ui.components.colorpicker.ColorPickerPopup; +import com.vaadin.ui.components.colorpicker.ColorSelector; + +/** + * An abstract class that defines default implementation for a color picker + * component. + * + * @since 7.0.0 + */ +public abstract class AbstractColorPicker extends AbstractComponent implements + CloseListener, ColorSelector { + private static final Method COLOR_CHANGE_METHOD; + static { + try { + COLOR_CHANGE_METHOD = ColorChangeListener.class.getDeclaredMethod( + "colorChanged", new Class[] { ColorChangeEvent.class }); + } catch (final java.lang.NoSuchMethodException e) { + // This should never happen + throw new java.lang.RuntimeException( + "Internal error finding methods in ColorPicker"); + } + } + + /** + * Interface for converting 2d-coordinates to a Color + */ + public interface Coordinates2Color { + + /** + * Calculate color from coordinates + * + * @param x + * the x-coordinate + * @param y + * the y-coordinate + * + * @return the color + */ + public Color calculate(int x, int y); + + /** + * Calculate coordinates from color + * + * @param c + * the c + * + * @return the integer array with the coordinates + */ + public int[] calculate(Color c); + } + + public enum PopupStyle { + POPUP_NORMAL("normal"), POPUP_SIMPLE("simple"); + + private String style; + + PopupStyle(String styleName) { + style = styleName; + } + + @Override + public String toString() { + return style; + } + } + + private ColorPickerServerRpc rpc = new ColorPickerServerRpc() { + + @Override + public void openPopup(boolean open) { + showPopup(open); + } + }; + + protected static final String STYLENAME_DEFAULT = "v-colorpicker"; + protected static final String STYLENAME_BUTTON = "v-button"; + protected static final String STYLENAME_AREA = "v-colorpicker-area"; + + protected PopupStyle popupStyle = PopupStyle.POPUP_NORMAL; + + /** The popup window. */ + private ColorPickerPopup window; + + /** The color. */ + protected Color color; + + /** The UI. */ + private UI parent; + + protected String popupCaption = null; + private int positionX = 0; + private int positionY = 0; + + protected boolean rgbVisible = true; + protected boolean hsvVisible = true; + protected boolean swatchesVisible = true; + protected boolean historyVisible = true; + protected boolean textfieldVisible = true; + + /** + * Instantiates a new color picker. + */ + public AbstractColorPicker() { + this("Colors", Color.WHITE); + } + + /** + * Instantiates a new color picker. + * + * @param popupCaption + * the caption of the popup window + */ + public AbstractColorPicker(String popupCaption) { + this(popupCaption, Color.WHITE); + } + + /** + * Instantiates a new color picker. + * + * @param popupCaption + * the caption of the popup window + * @param initialColor + * the initial color + */ + public AbstractColorPicker(String popupCaption, Color initialColor) { + super(); + registerRpc(rpc); + setColor(initialColor); + this.popupCaption = popupCaption; + setDefaultStyles(); + setCaption(""); + } + + @Override + public void setColor(Color color) { + this.color = color; + + if (window != null) { + window.setColor(color); + } + getState().color = color.getCSS(); + } + + @Override + public Color getColor() { + return color; + } + + /** + * Set true if the component should show a default caption (css-code for the + * currently selected color, e.g. #ffffff) when no other caption is + * available. + * + * @param enabled + */ + public void setDefaultCaptionEnabled(boolean enabled) { + getState().showDefaultCaption = enabled; + } + + /** + * Returns true if the component shows the default caption (css-code for the + * currently selected color, e.g. #ffffff) if no other caption is available. + */ + public boolean isDefaultCaptionEnabled() { + return getState().showDefaultCaption; + } + + /** + * Sets the position of the popup window + * + * @param x + * the x-coordinate + * @param y + * the y-coordinate + */ + public void setPosition(int x, int y) { + positionX = x; + positionY = y; + + if (window != null) { + window.setPositionX(x); + window.setPositionY(y); + } + } + + @Override + public void addColorChangeListener(ColorChangeListener listener) { + addListener(ColorChangeEvent.class, listener, COLOR_CHANGE_METHOD); + } + + @Override + public void removeColorChangeListener(ColorChangeListener listener) { + removeListener(ColorChangeEvent.class, listener); + } + + @Override + public void windowClose(CloseEvent e) { + if (e.getWindow() == window) { + getState().popupVisible = false; + } + } + + /** + * Fired when a color change event occurs + * + * @param event + * The color change event + */ + protected void colorChanged(ColorChangeEvent event) { + setColor(event.getColor()); + fireColorChanged(); + } + + /** + * Notifies the listeners that the selected color has changed + */ + public void fireColorChanged() { + fireEvent(new ColorChangeEvent(this, color)); + } + + /** + * The style for the popup window + * + * @param style + * The style + */ + public void setPopupStyle(PopupStyle style) { + popupStyle = style; + + switch (style) { + case POPUP_NORMAL: { + setRGBVisibility(true); + setHSVVisibility(true); + setSwatchesVisibility(true); + setHistoryVisibility(true); + setTextfieldVisibility(true); + break; + } + + case POPUP_SIMPLE: { + setRGBVisibility(false); + setHSVVisibility(false); + setSwatchesVisibility(true); + setHistoryVisibility(false); + setTextfieldVisibility(false); + break; + } + } + } + + /** + * Set the visibility of the RGB Tab + * + * @param visible + * The visibility + */ + public void setRGBVisibility(boolean visible) { + + if (!visible && !hsvVisible && !swatchesVisible) { + throw new IllegalArgumentException("Cannot hide all tabs."); + } + + rgbVisible = visible; + if (window != null) { + window.setRGBTabVisible(visible); + } + } + + /** + * Set the visibility of the HSV Tab + * + * @param visible + * The visibility + */ + public void setHSVVisibility(boolean visible) { + if (!visible && !rgbVisible && !swatchesVisible) { + throw new IllegalArgumentException("Cannot hide all tabs."); + } + + hsvVisible = visible; + if (window != null) { + window.setHSVTabVisible(visible); + } + } + + /** + * Set the visibility of the Swatches Tab + * + * @param visible + * The visibility + */ + public void setSwatchesVisibility(boolean visible) { + if (!visible && !hsvVisible && !rgbVisible) { + throw new IllegalArgumentException("Cannot hide all tabs."); + } + + swatchesVisible = visible; + if (window != null) { + window.setSwatchesTabVisible(visible); + } + } + + /** + * Sets the visibility of the Color History + * + * @param visible + * The visibility + */ + public void setHistoryVisibility(boolean visible) { + historyVisible = visible; + if (window != null) { + window.setHistoryVisible(visible); + } + } + + /** + * Sets the visibility of the CSS color code text field + * + * @param visible + * The visibility + */ + public void setTextfieldVisibility(boolean visible) { + textfieldVisible = visible; + if (window != null) { + window.setPreviewVisible(visible); + } + } + + @Override + protected ColorPickerState getState() { + return (ColorPickerState) super.getState(); + } + + /** + * Sets the default styles of the component + * + */ + abstract protected void setDefaultStyles(); + + /** + * Shows a popup-window for color selection. + */ + public void showPopup() { + showPopup(true); + } + + /** + * Hides a popup-window for color selection. + */ + public void hidePopup() { + showPopup(false); + } + + /** + * Shows or hides popup-window depending on the given parameter. If there is + * no such window yet, one is created. + * + * @param open + */ + protected void showPopup(boolean open) { + if (open && !isReadOnly()) { + if (parent == null) { + parent = getUI(); + } + + if (window == null) { + + // Create the popup + window = new ColorPickerPopup(color); + window.setCaption(popupCaption); + + window.setRGBTabVisible(rgbVisible); + window.setHSVTabVisible(hsvVisible); + window.setSwatchesTabVisible(swatchesVisible); + window.setHistoryVisible(historyVisible); + window.setPreviewVisible(textfieldVisible); + + window.setImmediate(true); + window.addCloseListener(this); + window.addColorChangeListener(new ColorChangeListener() { + public void colorChanged(ColorChangeEvent event) { + AbstractColorPicker.this.colorChanged(event); + } + }); + + window.getHistory().setColor(color); + parent.addWindow(window); + window.setVisible(true); + window.setPositionX(positionX); + window.setPositionY(positionY); + + } else if (!parent.equals(window.getParent())) { + + window.setRGBTabVisible(rgbVisible); + window.setHSVTabVisible(hsvVisible); + window.setSwatchesTabVisible(swatchesVisible); + window.setHistoryVisible(historyVisible); + window.setPreviewVisible(textfieldVisible); + + window.setColor(color); + window.getHistory().setColor(color); + window.setVisible(true); + parent.addWindow(window); + } + + } else if (window != null) { + window.setVisible(false); + parent.removeWindow(window); + } + getState().popupVisible = open; + } + + /** + * Set whether the caption text is rendered as HTML or not. You might need + * to re-theme component to allow higher content than the original text + * style. + * + * If set to true, the captions are passed to the browser as html and the + * developer is responsible for ensuring no harmful html is used. If set to + * false, the content is passed to the browser as plain text. + * + * @param htmlContentAllowed + * <code>true</code> if caption is rendered as HTML, + * <code>false</code> otherwise + */ + public void setHtmlContentAllowed(boolean htmlContentAllowed) { + getState().htmlContentAllowed = htmlContentAllowed; + } + + /** + * Return HTML rendering setting + * + * @return <code>true</code> if the caption text is to be rendered as HTML, + * <code>false</code> otherwise + */ + public boolean isHtmlContentAllowed() { + return getState().htmlContentAllowed; + } +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/ColorPicker.java b/server/src/com/vaadin/ui/ColorPicker.java new file mode 100644 index 0000000000..1e729badcc --- /dev/null +++ b/server/src/com/vaadin/ui/ColorPicker.java @@ -0,0 +1,64 @@ +package com.vaadin.ui; + +import com.vaadin.shared.ui.colorpicker.Color; + +/** + * A class that defines default (button-like) implementation for a color picker + * component. + * + * @since 7.0.0 + * + * @see ColorPickerArea + * + */ +public class ColorPicker extends AbstractColorPicker { + + /** + * Instantiates a new color picker. + */ + public ColorPicker() { + super(); + } + + /** + * Instantiates a new color picker. + * + * @param popupCaption + * caption of the color select popup + */ + public ColorPicker(String popupCaption) { + super(popupCaption); + } + + /** + * Instantiates a new color picker. + * + * @param popupCaption + * caption of the color select popup + * @param initialColor + * the initial color + */ + public ColorPicker(String popupCaption, Color initialColor) { + super(popupCaption, initialColor); + setDefaultCaptionEnabled(true); + } + + @Override + protected void setDefaultStyles() { + setPrimaryStyleName(STYLENAME_BUTTON); + addStyleName(STYLENAME_DEFAULT); + } + + @Override + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); + + if (isDefaultCaptionEnabled() + && ((getState().caption == null || "" + .equals(getState().caption))) + && "".equals(getState().width)) { + getState().width = "100px"; + } + } + +} diff --git a/server/src/com/vaadin/ui/ColorPickerArea.java b/server/src/com/vaadin/ui/ColorPickerArea.java new file mode 100644 index 0000000000..31deed4449 --- /dev/null +++ b/server/src/com/vaadin/ui/ColorPickerArea.java @@ -0,0 +1,62 @@ +package com.vaadin.ui; + +import com.vaadin.shared.ui.colorpicker.Color; + +/** + * A class that defines area-like implementation for a color picker component. + * + * @since 7.0.0 + * + * @see ColorPicker + * + */ +public class ColorPickerArea extends AbstractColorPicker { + + /** + * Instantiates a new color picker. + */ + public ColorPickerArea() { + super(); + } + + /** + * Instantiates a new color picker. + * + * @param popupCaption + * caption of the color select popup + */ + public ColorPickerArea(String popupCaption) { + super(popupCaption); + } + + /** + * Instantiates a new color picker. + * + * @param popupCaption + * caption of the color select popup + * @param initialColor + * the initial color + */ + public ColorPickerArea(String popupCaption, Color initialColor) { + super(popupCaption, initialColor); + setDefaultCaptionEnabled(false); + } + + @Override + protected void setDefaultStyles() { + // state already has correct default + } + + @Override + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); + + if ("".equals(getState().height)) { + getState().height = "30px"; + } + if ("".equals(getState().width)) { + getState().width = "30px"; + } + } + +} diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorChangeEvent.java b/server/src/com/vaadin/ui/components/colorpicker/ColorChangeEvent.java new file mode 100644 index 0000000000..8ad935f9d3 --- /dev/null +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorChangeEvent.java @@ -0,0 +1,28 @@ +package com.vaadin.ui.components.colorpicker; + +import com.vaadin.shared.ui.colorpicker.Color; +import com.vaadin.ui.Component; +import com.vaadin.ui.Component.Event; + +/** + * The color changed event which is passed to the listeners when a color change + * occurs. + * + * @since 7.0.0 + */ +public class ColorChangeEvent extends Event { + private final Color color; + + public ColorChangeEvent(Component source, Color color) { + super(source); + + this.color = color; + } + + /** + * Returns the new color. + */ + public Color getColor() { + return color; + } +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorChangeListener.java b/server/src/com/vaadin/ui/components/colorpicker/ColorChangeListener.java new file mode 100644 index 0000000000..9f8ea0ff26 --- /dev/null +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorChangeListener.java @@ -0,0 +1,27 @@ +package com.vaadin.ui.components.colorpicker; + +import java.io.Serializable; + +/** + * The listener interface for receiving colorChange events. The class that is + * interested in processing a {@link ColorChangeEvent} implements this + * interface, and the object created with that class is registered with a + * component using the component's <code>addColorChangeListener</code> method. + * When the colorChange event occurs, that object's appropriate method is + * invoked. + * + * @since 7.0.0 + * + * @see ColorChangeEvent + */ +public interface ColorChangeListener extends Serializable { + + /** + * Called when a new color has been selected. + * + * @param event + * An event containing information about the color change. + */ + void colorChanged(ColorChangeEvent event); + +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGradient.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGradient.java new file mode 100644 index 0000000000..ddd61f37b2 --- /dev/null +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGradient.java @@ -0,0 +1,129 @@ +package com.vaadin.ui.components.colorpicker; + +import java.lang.reflect.Method; + +import com.vaadin.shared.ui.colorpicker.Color; +import com.vaadin.shared.ui.colorpicker.ColorPickerGradientServerRpc; +import com.vaadin.shared.ui.colorpicker.ColorPickerGradientState; +import com.vaadin.ui.AbstractColorPicker.Coordinates2Color; +import com.vaadin.ui.AbstractComponent; + +/** + * A component that represents a color gradient within a color picker. + * + * @since 7.0.0 + */ +public class ColorPickerGradient extends AbstractComponent implements + ColorSelector { + + private static final Method COLOR_CHANGE_METHOD; + static { + try { + COLOR_CHANGE_METHOD = ColorChangeListener.class.getDeclaredMethod( + "colorChanged", new Class[] { ColorChangeEvent.class }); + } catch (final java.lang.NoSuchMethodException e) { + // This should never happen + throw new java.lang.RuntimeException( + "Internal error finding methods in ColorPicker"); + } + } + + private ColorPickerGradientServerRpc rpc = new ColorPickerGradientServerRpc() { + + @Override + public void select(int cursorX, int cursorY) { + x = cursorX; + y = cursorY; + color = converter.calculate(x, y); + + fireColorChanged(color); + } + }; + + /** The converter. */ + private final Coordinates2Color converter; + + /** The foreground color. */ + private Color color; + + /** The x-coordinate. */ + private int x = 0; + + /** The y-coordinate. */ + private int y = 0; + + /** The background color. */ + private Color backgroundColor; + + /** + * Instantiates a new color picker gradient. + * + * @param id + * the id + * @param converter + * the converter + */ + public ColorPickerGradient(String id, Coordinates2Color converter) { + registerRpc(rpc); + getState().id = id; + // width and height must be set here instead of in theme, otherwise + // coordinate calculations fail + getState().width = "220px"; + getState().height = "220px"; + this.converter = converter; + } + + @Override + public void setColor(Color c) { + color = c; + + int[] coords = converter.calculate(c); + x = coords[0]; + y = coords[1]; + + getState().cursorX = x; + getState().cursorY = y; + + } + + @Override + public void addColorChangeListener(ColorChangeListener listener) { + addListener(ColorChangeEvent.class, listener, COLOR_CHANGE_METHOD); + } + + @Override + public void removeColorChangeListener(ColorChangeListener listener) { + removeListener(ColorChangeEvent.class, listener); + } + + /** + * Sets the background color. + * + * @param color + * the new background color + */ + public void setBackgroundColor(Color color) { + backgroundColor = color; + getState().bgColor = color.getCSS(); + } + + @Override + public Color getColor() { + return color; + } + + /** + * Notifies the listeners that the color has changed + * + * @param color + * The color which it changed to + */ + public void fireColorChanged(Color color) { + fireEvent(new ColorChangeEvent(this, color)); + } + + @Override + protected ColorPickerGradientState getState() { + return (ColorPickerGradientState) super.getState(); + } +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGrid.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGrid.java new file mode 100644 index 0000000000..37e70c328f --- /dev/null +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGrid.java @@ -0,0 +1,240 @@ +package com.vaadin.ui.components.colorpicker; + +import java.awt.Point; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import com.vaadin.shared.ui.colorpicker.Color; +import com.vaadin.shared.ui.colorpicker.ColorPickerGridServerRpc; +import com.vaadin.shared.ui.colorpicker.ColorPickerGridState; +import com.vaadin.ui.AbstractComponent; + +/** + * A component that represents a color selection grid within a color picker. + * + * @since 7.0.0 + */ +public class ColorPickerGrid extends AbstractComponent implements ColorSelector { + + private static final String STYLENAME = "v-colorpicker-grid"; + + private static final Method COLOR_CHANGE_METHOD; + static { + try { + COLOR_CHANGE_METHOD = ColorChangeListener.class.getDeclaredMethod( + "colorChanged", new Class[] { ColorChangeEvent.class }); + } catch (final java.lang.NoSuchMethodException e) { + // This should never happen + throw new java.lang.RuntimeException( + "Internal error finding methods in ColorPicker"); + } + } + + private ColorPickerGridServerRpc rpc = new ColorPickerGridServerRpc() { + + @Override + public void select(int x, int y) { + ColorPickerGrid.this.x = x; + ColorPickerGrid.this.y = y; + + fireColorChanged(colorGrid[y][x]); + } + + @Override + public void refresh() { + for (int row = 0; row < rows; row++) { + for (int col = 0; col < columns; col++) { + changedColors.put(new Point(row, col), colorGrid[row][col]); + } + } + sendChangedColors(); + markAsDirty(); + } + }; + + /** The x-coordinate. */ + private int x = 0; + + /** The y-coordinate. */ + private int y = 0; + + /** The rows. */ + private int rows; + + /** The columns. */ + private int columns; + + /** The color grid. */ + private Color[][] colorGrid = new Color[1][1]; + + /** The changed colors. */ + private final Map<Point, Color> changedColors = new HashMap<Point, Color>(); + + /** + * Instantiates a new color picker grid. + */ + public ColorPickerGrid() { + registerRpc(rpc); + setPrimaryStyleName(STYLENAME); + setColorGrid(new Color[1][1]); + setColor(Color.WHITE); + } + + /** + * Instantiates a new color picker grid. + * + * @param rows + * the rows + * @param columns + * the columns + */ + public ColorPickerGrid(int rows, int columns) { + registerRpc(rpc); + setPrimaryStyleName(STYLENAME); + setColorGrid(new Color[rows][columns]); + setColor(Color.WHITE); + } + + /** + * Instantiates a new color picker grid. + * + * @param colors + * the colors + */ + public ColorPickerGrid(Color[][] colors) { + registerRpc(rpc); + setPrimaryStyleName(STYLENAME); + setColorGrid(colors); + } + + private void setColumnCount(int columns) { + this.columns = columns; + getState().columnCount = columns; + } + + private void setRowCount(int rows) { + this.rows = rows; + getState().rowCount = rows; + } + + private void sendChangedColors() { + if (!changedColors.isEmpty()) { + String[] colors = new String[changedColors.size()]; + String[] XCoords = new String[changedColors.size()]; + String[] YCoords = new String[changedColors.size()]; + int counter = 0; + for (Point p : changedColors.keySet()) { + Color c = changedColors.get(p); + if (c == null) { + continue; + } + + String color = c.getCSS(); + + colors[counter] = color; + XCoords[counter] = String.valueOf((int) p.getX()); + YCoords[counter] = String.valueOf((int) p.getY()); + counter++; + } + getState().changedColor = colors; + getState().changedX = XCoords; + getState().changedY = YCoords; + + changedColors.clear(); + } + } + + /** + * Sets the color grid. + * + * @param colors + * the new color grid + */ + public void setColorGrid(Color[][] colors) { + setRowCount(colors.length); + setColumnCount(colors[0].length); + colorGrid = colors; + + for (int row = 0; row < rows; row++) { + for (int col = 0; col < columns; col++) { + changedColors.put(new Point(row, col), colorGrid[row][col]); + } + } + sendChangedColors(); + + markAsDirty(); + } + + /** + * Adds a color change listener + * + * @param listener + * The color change listener + */ + public void addColorChangeListener(ColorChangeListener listener) { + addListener(ColorChangeEvent.class, listener, COLOR_CHANGE_METHOD); + } + + @Override + public Color getColor() { + return colorGrid[x][y]; + } + + /** + * Removes a color change listener + * + * @param listener + * The listener + */ + public void removeColorChangeListener(ColorChangeListener listener) { + removeListener(ColorChangeEvent.class, listener); + } + + @Override + public void setColor(Color color) { + colorGrid[x][y] = color; + changedColors.put(new Point(x, y), color); + sendChangedColors(); + markAsDirty(); + } + + /** + * Sets the position. + * + * @param x + * the x + * @param y + * the y + */ + public void setPosition(int x, int y) { + if (x >= 0 && x < columns && y >= 0 && y < rows) { + this.x = x; + this.y = y; + } + } + + /** + * Gets the position. + * + * @return the position + */ + public int[] getPosition() { + return new int[] { x, y }; + } + + /** + * Notifies the listeners that a color change has occurred + * + * @param color + * The color which it changed to + */ + public void fireColorChanged(Color color) { + fireEvent(new ColorChangeEvent(this, color)); + } + + @Override + protected ColorPickerGridState getState() { + return (ColorPickerGridState) super.getState(); + } +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java new file mode 100644 index 0000000000..81d521237e --- /dev/null +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java @@ -0,0 +1,200 @@ +package com.vaadin.ui.components.colorpicker; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; + +import com.vaadin.shared.ui.colorpicker.Color; +import com.vaadin.ui.CustomComponent; + +/** + * A component that represents color selection history within a color picker. + * + * @since 7.0.0 + */ +public class ColorPickerHistory extends CustomComponent implements + ColorSelector, ColorChangeListener { + + private static final String STYLENAME = "v-colorpicker-history"; + + private static final Method COLOR_CHANGE_METHOD; + static { + try { + COLOR_CHANGE_METHOD = ColorChangeListener.class.getDeclaredMethod( + "colorChanged", new Class[] { ColorChangeEvent.class }); + } catch (final java.lang.NoSuchMethodException e) { + // This should never happen + throw new java.lang.RuntimeException( + "Internal error finding methods in ColorPicker"); + } + } + + /** The rows. */ + private static final int rows = 4; + + /** The columns. */ + private static final int columns = 15; + + /** Temporary color history for when the component is detached. */ + private ArrayBlockingQueue<Color> tempHistory = new ArrayBlockingQueue<Color>( + rows * columns); + + /** The grid. */ + private final ColorPickerGrid grid; + + /** + * Instantiates a new color picker history. + */ + public ColorPickerHistory() { + setPrimaryStyleName(STYLENAME); + + grid = new ColorPickerGrid(rows, columns); + grid.setWidth("100%"); + grid.setPosition(0, 0); + grid.addColorChangeListener(this); + + setCompositionRoot(grid); + } + + @Override + public void attach() { + super.attach(); + createColorHistoryIfNecessary(); + } + + private void createColorHistoryIfNecessary() { + List<Color> tempColors = new ArrayList<Color>(tempHistory); + if (getSession().getAttribute("colorPickerHistory") == null) { + getSession().setAttribute("colorPickerHistory", + new ArrayBlockingQueue<Color>(rows * columns)); + } + for (Color color : tempColors) { + setColor(color); + } + tempHistory.clear(); + } + + @SuppressWarnings("unchecked") + private ArrayBlockingQueue<Color> getColorHistory() { + if (getSession() != null) { + Object colorHistory = getSession().getAttribute( + "colorPickerHistory"); + if (colorHistory instanceof ArrayBlockingQueue<?>) { + return (ArrayBlockingQueue<Color>) colorHistory; + } + } + return tempHistory; + } + + @Override + public void setHeight(String height) { + super.setHeight(height); + grid.setHeight(height); + } + + @Override + public void setColor(Color color) { + + ArrayBlockingQueue<Color> colorHistory = getColorHistory(); + + // Check that the color does not already exist + boolean exists = false; + Iterator<Color> iter = colorHistory.iterator(); + while (iter.hasNext()) { + if (color.equals(iter.next())) { + exists = true; + break; + } + } + + // If the color does not exist then add it + if (!exists) { + if (!colorHistory.offer(color)) { + colorHistory.poll(); + colorHistory.offer(color); + } + } + + List<Color> colorList = new ArrayList<Color>(colorHistory); + + // Invert order of colors + Collections.reverse(colorList); + + // Move the selected color to the front of the list + Collections.swap(colorList, colorList.indexOf(color), 0); + + // Create 2d color map + Color[][] colors = new Color[rows][columns]; + iter = colorList.iterator(); + + for (int row = 0; row < rows; row++) { + for (int col = 0; col < columns; col++) { + if (iter.hasNext()) { + colors[row][col] = iter.next(); + } else { + colors[row][col] = Color.WHITE; + } + } + } + + grid.setColorGrid(colors); + grid.markAsDirty(); + } + + @Override + public Color getColor() { + return getColorHistory().peek(); + } + + /** + * Gets the history. + * + * @return the history + */ + public List<Color> getHistory() { + ArrayBlockingQueue<Color> colorHistory = getColorHistory(); + Color[] array = colorHistory.toArray(new Color[colorHistory.size()]); + return Collections.unmodifiableList(Arrays.asList(array)); + } + + /** + * Checks if the history contains given color. + * + * @param c + * the color + * + * @return true, if successful + */ + public boolean hasColor(Color c) { + return getColorHistory().contains(c); + } + + /** + * Adds a color change listener + * + * @param listener + * The listener + */ + public void addColorChangeListener(ColorChangeListener listener) { + addListener(ColorChangeEvent.class, listener, COLOR_CHANGE_METHOD); + } + + /** + * Removes a color change listener + * + * @param listener + * The listener + */ + public void removeColorChangeListener(ColorChangeListener listener) { + removeListener(ColorChangeEvent.class, listener); + } + + @Override + public void colorChanged(ColorChangeEvent event) { + fireEvent(new ColorChangeEvent(this, event.getColor())); + } +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java new file mode 100644 index 0000000000..ddfbf7381e --- /dev/null +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java @@ -0,0 +1,766 @@ +package com.vaadin.ui.components.colorpicker; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.shared.ui.MarginInfo; +import com.vaadin.shared.ui.colorpicker.Color; +import com.vaadin.ui.AbstractColorPicker.Coordinates2Color; +import com.vaadin.ui.Alignment; +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.HorizontalLayout; +import com.vaadin.ui.Layout; +import com.vaadin.ui.Slider; +import com.vaadin.ui.Slider.ValueOutOfBoundsException; +import com.vaadin.ui.TabSheet; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.Window; + +/** + * A component that represents color selection popup within a color picker. + * + * @since 7.0.0 + */ +public class ColorPickerPopup extends Window implements ClickListener, + ColorChangeListener, ColorSelector { + + private static final String STYLENAME = "v-colorpicker-popup"; + + private static final Method COLOR_CHANGE_METHOD; + static { + try { + COLOR_CHANGE_METHOD = ColorChangeListener.class.getDeclaredMethod( + "colorChanged", new Class[] { ColorChangeEvent.class }); + } catch (final java.lang.NoSuchMethodException e) { + // This should never happen + throw new java.lang.RuntimeException( + "Internal error finding methods in ColorPicker"); + } + } + + /** The tabs. */ + private final TabSheet tabs = new TabSheet(); + + private Component rgbTab; + + private Component hsvTab; + + private Component swatchesTab; + + /** The layout. */ + private final VerticalLayout layout; + + /** The ok button. */ + private final Button ok = new Button("OK"); + + /** The cancel button. */ + private final Button cancel = new Button("Cancel"); + + /** The resize button. */ + private final Button resize = new Button("show/hide history"); + + /** The selected color. */ + private Color selectedColor = Color.WHITE; + + /** The history. */ + private ColorPickerHistory history; + + /** The history container. */ + private Layout historyContainer; + + /** The rgb gradient. */ + private ColorPickerGradient rgbGradient; + + /** The hsv gradient. */ + private ColorPickerGradient hsvGradient; + + /** The red slider. */ + private Slider redSlider; + + /** The green slider. */ + private Slider greenSlider; + + /** The blue slider. */ + private Slider blueSlider; + + /** The hue slider. */ + private Slider hueSlider; + + /** The saturation slider. */ + private Slider saturationSlider; + + /** The value slider. */ + private Slider valueSlider; + + /** The preview on the rgb tab. */ + private ColorPickerPreview rgbPreview; + + /** The preview on the hsv tab. */ + private ColorPickerPreview hsvPreview; + + /** The preview on the swatches tab. */ + private ColorPickerPreview selPreview; + + /** The color select. */ + private ColorPickerSelect colorSelect; + + /** The selectors. */ + private final Set<ColorSelector> selectors = new HashSet<ColorSelector>(); + + /** + * Set true while the slider values are updated after colorChange. When + * true, valueChange reactions from the sliders are disabled, because + * otherwise the set color may become corrupted as it is repeatedly re-set + * in valueChangeListeners using values from sliders that may not have been + * updated yet. + */ + private boolean updatingColors = false; + + /** + * Instantiates a new color picker popup. + */ + public ColorPickerPopup(Color initialColor) { + super(); + + selectedColor = initialColor; + + // Set the layout + layout = new VerticalLayout(); + layout.setSpacing(false); + layout.setMargin(false); + layout.setWidth("100%"); + layout.setHeight(null); + + setContent(layout); + setStyleName(STYLENAME); + setResizable(false); + setImmediate(true); + + initContents(); + } + + private void initContents() { + // Create the history + history = new ColorPickerHistory(); + history.addColorChangeListener(this); + + // Create the preview on the rgb tab + rgbPreview = new ColorPickerPreview(selectedColor); + rgbPreview.setWidth("240px"); + rgbPreview.setHeight("20px"); + rgbPreview.addColorChangeListener(this); + selectors.add(rgbPreview); + + // Create the preview on the hsv tab + hsvPreview = new ColorPickerPreview(selectedColor); + hsvPreview.setWidth("240px"); + hsvPreview.setHeight("20px"); + hsvPreview.addColorChangeListener(this); + selectors.add(hsvPreview); + + // Create the preview on the swatches tab + selPreview = new ColorPickerPreview(selectedColor); + selPreview.setWidth("100%"); + selPreview.setHeight("20px"); + selPreview.addColorChangeListener(this); + selectors.add(selPreview); + + // Create the tabs + rgbTab = createRGBTab(selectedColor); + tabs.addTab(rgbTab, "RGB", null); + + hsvTab = createHSVTab(selectedColor); + tabs.addTab(hsvTab, "HSV", null); + + swatchesTab = createSelectTab(); + tabs.addTab(swatchesTab, "Swatches", null); + + // Add the tabs + tabs.setWidth("100%"); + + layout.addComponent(tabs); + + // Add the history + history.setWidth("97%"); + history.setHeight("22px"); + + // Create the default colors + List<Color> defaultColors = new ArrayList<Color>(); + defaultColors.add(Color.BLACK); + defaultColors.add(Color.WHITE); + + // Create the history + VerticalLayout innerContainer = new VerticalLayout(); + innerContainer.setWidth("100%"); + innerContainer.setHeight(null); + innerContainer.addComponent(history); + + VerticalLayout outerContainer = new VerticalLayout(); + outerContainer.setWidth("99%"); + outerContainer.setHeight("27px"); + outerContainer.addComponent(innerContainer); + historyContainer = outerContainer; + + layout.addComponent(historyContainer); + + // Add the resize button for the history + resize.addClickListener(this); + resize.setData(new Boolean(false)); + resize.setWidth("100%"); + resize.setHeight("10px"); + resize.setPrimaryStyleName("resize-button"); + layout.addComponent(resize); + + // Add the buttons + ok.setWidth("70px"); + ok.addClickListener(this); + + cancel.setWidth("70px"); + cancel.addClickListener(this); + + HorizontalLayout buttons = new HorizontalLayout(); + buttons.addComponent(ok); + buttons.addComponent(cancel); + buttons.setWidth("100%"); + buttons.setHeight("30px"); + buttons.setComponentAlignment(ok, Alignment.MIDDLE_CENTER); + buttons.setComponentAlignment(cancel, Alignment.MIDDLE_CENTER); + layout.addComponent(buttons); + } + + /** + * Creates the RGB tab. + * + * @return the component + */ + private Component createRGBTab(Color color) { + VerticalLayout rgbLayout = new VerticalLayout(); + rgbLayout.setMargin(new MarginInfo(false, false, true, false)); + rgbLayout.addComponent(rgbPreview); + rgbLayout.setStyleName("rgbtab"); + + // Add the RGB color gradient + rgbGradient = new ColorPickerGradient("rgb-gradient", RGBConverter); + rgbGradient.setColor(color); + rgbGradient.addColorChangeListener(this); + rgbLayout.addComponent(rgbGradient); + selectors.add(rgbGradient); + + // Add the RGB sliders + VerticalLayout sliders = new VerticalLayout(); + sliders.setStyleName("rgb-sliders"); + + redSlider = createRGBSlider("Red", "red"); + + try { + redSlider.setValue(((Integer) color.getRed()).doubleValue()); + } catch (ValueOutOfBoundsException e) { + } + + redSlider.addValueChangeListener(new ValueChangeListener() { + public void valueChange(ValueChangeEvent event) { + double red = (Double) event.getProperty().getValue(); + if (!updatingColors) { + Color newColor = new Color((int) red, selectedColor + .getGreen(), selectedColor.getBlue()); + setColor(newColor); + } + } + }); + + sliders.addComponent(redSlider); + + greenSlider = createRGBSlider("Green", "green"); + + try { + greenSlider.setValue(((Integer) color.getGreen()).doubleValue()); + } catch (ValueOutOfBoundsException e) { + } + + greenSlider.addValueChangeListener(new ValueChangeListener() { + public void valueChange(ValueChangeEvent event) { + double green = (Double) event.getProperty().getValue(); + if (!updatingColors) { + Color newColor = new Color(selectedColor.getRed(), + (int) green, selectedColor.getBlue()); + setColor(newColor); + } + } + }); + sliders.addComponent(greenSlider); + + blueSlider = createRGBSlider("Blue", "blue"); + + try { + blueSlider.setValue(((Integer) color.getBlue()).doubleValue()); + } catch (ValueOutOfBoundsException e) { + } + + blueSlider.addValueChangeListener(new ValueChangeListener() { + public void valueChange(ValueChangeEvent event) { + double blue = (Double) event.getProperty().getValue(); + if (!updatingColors) { + Color newColor = new Color(selectedColor.getRed(), + selectedColor.getGreen(), (int) blue); + setColor(newColor); + } + } + }); + sliders.addComponent(blueSlider); + + rgbLayout.addComponent(sliders); + + return rgbLayout; + } + + private Slider createRGBSlider(String caption, String styleName) { + Slider redSlider = new Slider(caption, 0, 255); + redSlider.setImmediate(true); + redSlider.setStyleName("rgb-slider"); + redSlider.setWidth("220px"); + redSlider.addStyleName(styleName); + return redSlider; + } + + /** + * Creates the hsv tab. + * + * @return the component + */ + private Component createHSVTab(Color color) { + VerticalLayout hsvLayout = new VerticalLayout(); + hsvLayout.setMargin(new MarginInfo(false, false, true, false)); + hsvLayout.addComponent(hsvPreview); + hsvLayout.setStyleName("hsvtab"); + + // Add the hsv gradient + hsvGradient = new ColorPickerGradient("hsv-gradient", HSVConverter); + hsvGradient.setColor(color); + hsvGradient.addColorChangeListener(this); + hsvLayout.addComponent(hsvGradient); + selectors.add(hsvGradient); + + float[] hsv = color.getHSV(); + VerticalLayout sliders = new VerticalLayout(); + sliders.setStyleName("hsv-sliders"); + + hueSlider = new Slider("Hue", 0, 360); + try { + hueSlider.setValue(((Float) hsv[0]).doubleValue()); + } catch (ValueOutOfBoundsException e1) { + } + + hueSlider.setStyleName("hsv-slider"); + hueSlider.addStyleName("hue-slider"); + hueSlider.setWidth("220px"); + hueSlider.setImmediate(true); + hueSlider.addValueChangeListener(new ValueChangeListener() { + public void valueChange(ValueChangeEvent event) { + if (!updatingColors) { + float hue = (Float.parseFloat(event.getProperty() + .getValue().toString())) / 360f; + float saturation = (Float.parseFloat(saturationSlider + .getValue().toString())) / 100f; + float value = (Float.parseFloat(valueSlider.getValue() + .toString())) / 100f; + + // Set the color + Color color = new Color(Color.HSVtoRGB(hue, saturation, + value)); + setColor(color); + + /* + * Set the background color of the hue gradient. This has to + * be done here since in the conversion the base color + * information is lost when color is black/white + */ + Color bgColor = new Color(Color.HSVtoRGB(hue, 1f, 1f)); + hsvGradient.setBackgroundColor(bgColor); + } + } + }); + sliders.addComponent(hueSlider); + + saturationSlider = new Slider("Saturation", 0, 100); + + try { + saturationSlider.setValue(((Float) hsv[1]).doubleValue()); + } catch (ValueOutOfBoundsException e1) { + } + + saturationSlider.setStyleName("hsv-slider"); + saturationSlider.setWidth("220px"); + saturationSlider.setImmediate(true); + saturationSlider.addValueChangeListener(new ValueChangeListener() { + public void valueChange(ValueChangeEvent event) { + if (!updatingColors) { + float hue = (Float.parseFloat(hueSlider.getValue() + .toString())) / 360f; + float saturation = (Float.parseFloat(event.getProperty() + .getValue().toString())) / 100f; + float value = (Float.parseFloat(valueSlider.getValue() + .toString())) / 100f; + Color color = new Color(Color.HSVtoRGB(hue, saturation, + value)); + setColor(color); + } + } + }); + sliders.addComponent(saturationSlider); + + valueSlider = new Slider("Value", 0, 100); + + try { + valueSlider.setValue(((Float) hsv[2]).doubleValue()); + } catch (ValueOutOfBoundsException e1) { + } + + valueSlider.setStyleName("hsv-slider"); + valueSlider.setWidth("220px"); + valueSlider.setImmediate(true); + valueSlider.addValueChangeListener(new ValueChangeListener() { + public void valueChange(ValueChangeEvent event) { + if (!updatingColors) { + float hue = (Float.parseFloat(hueSlider.getValue() + .toString())) / 360f; + float saturation = (Float.parseFloat(saturationSlider + .getValue().toString())) / 100f; + float value = (Float.parseFloat(event.getProperty() + .getValue().toString())) / 100f; + + Color color = new Color(Color.HSVtoRGB(hue, saturation, + value)); + setColor(color); + } + } + }); + + sliders.addComponent(valueSlider); + hsvLayout.addComponent(sliders); + + return hsvLayout; + } + + /** + * Creates the select tab. + * + * @return the component + */ + private Component createSelectTab() { + VerticalLayout selLayout = new VerticalLayout(); + selLayout.setMargin(new MarginInfo(false, false, true, false)); + selLayout.addComponent(selPreview); + selLayout.addStyleName("seltab"); + + colorSelect = new ColorPickerSelect(); + colorSelect.addColorChangeListener(this); + selLayout.addComponent(colorSelect); + + return selLayout; + } + + @Override + public void buttonClick(ClickEvent event) { + // History resize was clicked + if (event.getButton() == resize) { + boolean state = (Boolean) resize.getData(); + + // minimize + if (state) { + historyContainer.setHeight("27px"); + history.setHeight("22px"); + + // maximize + } else { + historyContainer.setHeight("90px"); + history.setHeight("85px"); + } + + resize.setData(new Boolean(!state)); + } + + // Ok button was clicked + else if (event.getButton() == ok) { + history.setColor(getColor()); + fireColorChanged(); + close(); + } + + // Cancel button was clicked + else if (event.getButton() == cancel) { + close(); + } + + } + + /** + * Notifies the listeners that the color changed + */ + public void fireColorChanged() { + fireEvent(new ColorChangeEvent(this, getColor())); + } + + /** + * Gets the history. + * + * @return the history + */ + public ColorPickerHistory getHistory() { + return history; + } + + @Override + public void setColor(Color color) { + if (color == null) { + return; + } + + selectedColor = color; + + hsvGradient.setColor(selectedColor); + hsvPreview.setColor(selectedColor); + + rgbGradient.setColor(selectedColor); + rgbPreview.setColor(selectedColor); + + selPreview.setColor(selectedColor); + } + + @Override + public Color getColor() { + return selectedColor; + } + + /** + * Gets the color history. + * + * @return the color history + */ + public List<Color> getColorHistory() { + return Collections.unmodifiableList(history.getHistory()); + } + + @Override + public void colorChanged(ColorChangeEvent event) { + setColor(event.getColor()); + + updatingColors = true; + try { + redSlider + .setValue(((Integer) selectedColor.getRed()).doubleValue()); + blueSlider.setValue(((Integer) selectedColor.getBlue()) + .doubleValue()); + greenSlider.setValue(((Integer) selectedColor.getGreen()) + .doubleValue()); + + float[] hsv = selectedColor.getHSV(); + + hueSlider.setValue(((Float) (hsv[0] * 360f)).doubleValue()); + saturationSlider.setValue(((Float) (hsv[1] * 100f)).doubleValue()); + valueSlider.setValue(((Float) (hsv[2] * 100f)).doubleValue()); + + } catch (ValueOutOfBoundsException e) { + e.printStackTrace(); + } + updatingColors = false; + + for (ColorSelector s : selectors) { + if (event.getSource() != s && s != this + && s.getColor() != selectedColor) { + s.setColor(selectedColor); + } + } + } + + @Override + public void addColorChangeListener(ColorChangeListener listener) { + addListener(ColorChangeEvent.class, listener, COLOR_CHANGE_METHOD); + } + + @Override + public void removeColorChangeListener(ColorChangeListener listener) { + removeListener(ColorChangeEvent.class, listener); + } + + /** + * Checks the visibility of the given tab + * + * @param tab + * The tab to check + * @return true if tab is visible, false otherwise + */ + private boolean tabIsVisible(Component tab) { + Iterator<Component> tabIterator = tabs.getComponentIterator(); + while (tabIterator.hasNext()) { + if (tabIterator.next() == tab) { + return true; + } + } + return false; + } + + /** + * How many tabs are visible + * + * @return The number of tabs visible + */ + private int tabsNumVisible() { + Iterator<Component> tabIterator = tabs.getComponentIterator(); + int tabCounter = 0; + while (tabIterator.hasNext()) { + tabIterator.next(); + tabCounter++; + } + return tabCounter; + } + + /** + * Checks if tabs are needed and hides them if not + */ + private void checkIfTabsNeeded() { + tabs.hideTabs(tabsNumVisible() == 1); + } + + /** + * Set RGB tab visibility + * + * @param visible + * The visibility of the RGB tab + */ + public void setRGBTabVisible(boolean visible) { + if (visible && !tabIsVisible(rgbTab)) { + tabs.addTab(rgbTab, "RGB", null); + checkIfTabsNeeded(); + } else if (!visible && tabIsVisible(rgbTab)) { + tabs.removeComponent(rgbTab); + checkIfTabsNeeded(); + } + } + + /** + * Set HSV tab visibility + * + * @param visible + * The visibility of the HSV tab + */ + public void setHSVTabVisible(boolean visible) { + if (visible && !tabIsVisible(hsvTab)) { + tabs.addTab(hsvTab, "HSV", null); + checkIfTabsNeeded(); + } else if (!visible && tabIsVisible(hsvTab)) { + tabs.removeComponent(hsvTab); + checkIfTabsNeeded(); + } + } + + /** + * Set Swatches tab visibility + * + * @param visible + * The visibility of the Swatches tab + */ + public void setSwatchesTabVisible(boolean visible) { + if (visible && !tabIsVisible(swatchesTab)) { + tabs.addTab(swatchesTab, "Swatches", null); + checkIfTabsNeeded(); + } else if (!visible && tabIsVisible(swatchesTab)) { + tabs.removeComponent(swatchesTab); + checkIfTabsNeeded(); + } + } + + /** + * Set the History visibility + * + * @param visible + */ + public void setHistoryVisible(boolean visible) { + historyContainer.setVisible(visible); + resize.setVisible(visible); + } + + /** + * Set the preview visibility + * + * @param visible + */ + public void setPreviewVisible(boolean visible) { + hsvPreview.setVisible(visible); + rgbPreview.setVisible(visible); + selPreview.setVisible(visible); + } + + /** RGB color converter */ + private Coordinates2Color RGBConverter = new Coordinates2Color() { + + @Override + public Color calculate(int x, int y) { + float h = (x / 220f); + float s = 1f; + float v = 1f; + + if (y < 110) { + s = y / 110f; + } else if (y > 110) { + v = 1f - (y - 110f) / 110f; + } + + return new Color(Color.HSVtoRGB(h, s, v)); + } + + @Override + public int[] calculate(Color color) { + + float[] hsv = color.getHSV(); + + int x = Math.round(hsv[0] * 220f); + int y = 0; + + // lower half + if (hsv[1] == 1f) { + y = Math.round(110f - (hsv[1] + hsv[2]) * 110f); + } else { + y = Math.round(hsv[1] * 110f); + } + + return new int[] { x, y }; + } + }; + + /** HSV color converter */ + Coordinates2Color HSVConverter = new Coordinates2Color() { + public int[] calculate(Color color) { + + float[] hsv = color.getHSV(); + + // Calculate coordinates + int x = Math.round(hsv[2] * 220.0f); + int y = Math.round(220 - hsv[1] * 220.0f); + + // Create background color of clean color + Color bgColor = new Color(Color.HSVtoRGB(hsv[0], 1f, 1f)); + hsvGradient.setBackgroundColor(bgColor); + + return new int[] { x, y }; + } + + public Color calculate(int x, int y) { + float saturation = 1f - (y / 220.0f); + float value = (x / 220.0f); + float hue = Float.parseFloat(hueSlider.getValue().toString()) / 360f; + + Color color = new Color(Color.HSVtoRGB(hue, saturation, value)); + return color; + } + }; +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPreview.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPreview.java new file mode 100644 index 0000000000..cb6dba3aab --- /dev/null +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPreview.java @@ -0,0 +1,143 @@ +package com.vaadin.ui.components.colorpicker; + +import java.lang.reflect.Method; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.data.validator.RegexpValidator; +import com.vaadin.shared.ui.colorpicker.Color; +import com.vaadin.ui.Component; +import com.vaadin.ui.CssLayout; +import com.vaadin.ui.TextField; + +/** + * A component that represents color selection preview within a color picker. + * + * @since 7.0.0 + */ +public class ColorPickerPreview extends CssLayout implements ColorSelector, + ValueChangeListener { + + private static final String STYLE_DARK_COLOR = "v-textfield-dark"; + private static final String STYLE_LIGHT_COLOR = "v-textfield-light"; + + private static final Method COLOR_CHANGE_METHOD; + static { + try { + COLOR_CHANGE_METHOD = ColorChangeListener.class.getDeclaredMethod( + "colorChanged", new Class[] { ColorChangeEvent.class }); + } catch (final java.lang.NoSuchMethodException e) { + // This should never happen + throw new java.lang.RuntimeException( + "Internal error finding methods in ColorPicker"); + } + } + + /** The color. */ + private Color color; + + /** The field. */ + private final TextField field; + + /** The old value. */ + private String oldValue; + + /** + * Instantiates a new color picker preview. + */ + public ColorPickerPreview(Color color) { + setStyleName("v-colorpicker-preview"); + setImmediate(true); + + this.color = color; + + field = new TextField(); + field.setReadOnly(true); + field.setImmediate(true); + field.setSizeFull(); + field.setStyleName("v-colorpicker-preview-textfield"); + field.setData(this); + field.addValueChangeListener(this); + field.addValidator(new RegexpValidator("#[0-9a-fA-F]{6}", true, "")); + addComponent(field); + + setColor(color); + } + + @Override + public void setColor(Color color) { + this.color = color; + + // Unregister listener + field.removeValueChangeListener(this); + field.setReadOnly(false); + + String colorCSS = color.getCSS(); + field.setValue(colorCSS); + + if (field.isValid()) { + oldValue = colorCSS; + } else { + field.setValue(oldValue); + } + + // Re-register listener + field.setReadOnly(true); + field.addValueChangeListener(this); + + // Set the text color + field.removeStyleName(STYLE_DARK_COLOR); + field.removeStyleName(STYLE_LIGHT_COLOR); + if (this.color.getRed() + this.color.getGreen() + this.color.getBlue() < 3 * 128) { + field.addStyleName(STYLE_DARK_COLOR); + } else { + field.addStyleName(STYLE_LIGHT_COLOR); + } + + markAsDirty(); + } + + @Override + public Color getColor() { + return color; + } + + @Override + public void addColorChangeListener(ColorChangeListener listener) { + addListener(ColorChangeEvent.class, listener, COLOR_CHANGE_METHOD); + } + + @Override + public void removeColorChangeListener(ColorChangeListener listener) { + removeListener(ColorChangeEvent.class, listener); + } + + @Override + public void valueChange(ValueChangeEvent event) { + String value = (String) event.getProperty().getValue(); + + if (!field.isValid()) { + field.setValue(oldValue); + return; + } else { + oldValue = value; + } + + if (value != null && value.length() == 7) { + int red = Integer.parseInt(value.substring(1, 3), 16); + int green = Integer.parseInt(value.substring(3, 5), 16); + int blue = Integer.parseInt(value.substring(5, 7), 16); + color = new Color(red, green, blue); + + fireEvent(new ColorChangeEvent((Component) field.getData(), color)); + } + } + + /** + * Called when the component is refreshing + */ + @Override + protected String getCss(Component c) { + return "background: " + color.getCSS(); + } +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerSelect.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerSelect.java new file mode 100644 index 0000000000..08747cce3f --- /dev/null +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerSelect.java @@ -0,0 +1,218 @@ +package com.vaadin.ui.components.colorpicker; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.shared.ui.colorpicker.Color; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.CustomComponent; +import com.vaadin.ui.VerticalLayout; + +/** + * A component that represents color selection swatches within a color picker. + * + * @since 7.0.0 + */ +public class ColorPickerSelect extends CustomComponent implements + ColorSelector, ValueChangeListener { + + /** The range. */ + private final ComboBox range; + + /** The grid. */ + private final ColorPickerGrid grid; + + /** + * The Enum ColorRangePropertyId. + */ + private enum ColorRangePropertyId { + ALL("All colors"), RED("Red colors"), GREEN("Green colors"), BLUE( + "Blue colors"); + + /** The caption. */ + private String caption; + + /** + * Instantiates a new color range property id. + * + * @param caption + * the caption + */ + ColorRangePropertyId(String caption) { + this.caption = caption; + } + + @Override + public String toString() { + return caption; + } + } + + /** + * Instantiates a new color picker select. + * + * @param rows + * the rows + * @param columns + * the columns + */ + public ColorPickerSelect() { + + VerticalLayout layout = new VerticalLayout(); + setCompositionRoot(layout); + + setStyleName("colorselect"); + setWidth("100%"); + + range = new ComboBox(); + range.setImmediate(true); + range.setImmediate(true); + range.setNullSelectionAllowed(false); + range.setNewItemsAllowed(false); + range.setWidth("100%"); + range.addValueChangeListener(this); + + for (ColorRangePropertyId id : ColorRangePropertyId.values()) { + range.addItem(id); + } + range.select(ColorRangePropertyId.ALL); + + layout.addComponent(range); + + grid = new ColorPickerGrid(createAllColors(14, 10)); + grid.setWidth("100%"); + + layout.addComponent(grid); + } + + /** + * Creates the all colors. + * + * @param rows + * the rows + * @param columns + * the columns + * + * @return the color[][] + */ + private Color[][] createAllColors(int rows, int columns) { + Color[][] colors = new Color[rows][columns]; + + for (int row = 0; row < rows; row++) { + for (int col = 0; col < columns; col++) { + + // Create the color grid by varying the saturation and value + if (row < (rows - 1)) { + // Calculate new hue value + float hue = ((float) col / (float) columns); + float saturation = 1f; + float value = 1f; + + // For the upper half use value=1 and variable + // saturation + if (row < (rows / 2)) { + saturation = ((row + 1f) / (rows / 2f)); + } else { + value = 1f - ((row - (rows / 2f)) / (rows / 2f)); + } + + colors[row][col] = new Color(Color.HSVtoRGB(hue, + saturation, value)); + } + + // The last row should have the black&white gradient + else { + float hue = 0f; + float saturation = 0f; + float value = 1f - ((float) col / (float) columns); + + colors[row][col] = new Color(Color.HSVtoRGB(hue, + saturation, value)); + } + } + } + + return colors; + } + + /** + * Creates the color. + * + * @param color + * the color + * @param rows + * the rows + * @param columns + * the columns + * + * @return the color[][] + */ + private Color[][] createColors(Color color, int rows, int columns) { + Color[][] colors = new Color[rows][columns]; + + float[] hsv = color.getHSV(); + + float hue = hsv[0]; + float saturation = 1f; + float value = 1f; + + for (int row = 0; row < rows; row++) { + for (int col = 0; col < columns; col++) { + + int index = row * columns + col; + saturation = 1f; + value = 1f; + + if (index <= ((rows * columns) / 2)) { + saturation = index + / (((float) rows * (float) columns) / 2f); + } else { + index -= ((rows * columns) / 2); + value = 1f - index + / (((float) rows * (float) columns) / 2f); + } + + colors[row][col] = new Color(Color.HSVtoRGB(hue, saturation, + value)); + } + } + + return colors; + } + + @Override + public Color getColor() { + return grid.getColor(); + } + + @Override + public void setColor(Color color) { + grid.getColor(); + } + + @Override + public void addColorChangeListener(ColorChangeListener listener) { + grid.addColorChangeListener(listener); + } + + @Override + public void removeColorChangeListener(ColorChangeListener listener) { + grid.removeColorChangeListener(listener); + } + + @Override + public void valueChange(ValueChangeEvent event) { + if (grid == null) { + return; + } + + if (event.getProperty().getValue() == ColorRangePropertyId.ALL) { + grid.setColorGrid(createAllColors(14, 10)); + } else if (event.getProperty().getValue() == ColorRangePropertyId.RED) { + grid.setColorGrid(createColors(new Color(0xFF, 0, 0), 14, 10)); + } else if (event.getProperty().getValue() == ColorRangePropertyId.GREEN) { + grid.setColorGrid(createColors(new Color(0, 0xFF, 0), 14, 10)); + } else if (event.getProperty().getValue() == ColorRangePropertyId.BLUE) { + grid.setColorGrid(createColors(new Color(0, 0, 0xFF), 14, 10)); + } + } +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorSelector.java b/server/src/com/vaadin/ui/components/colorpicker/ColorSelector.java new file mode 100644 index 0000000000..8468666e26 --- /dev/null +++ b/server/src/com/vaadin/ui/components/colorpicker/ColorSelector.java @@ -0,0 +1,28 @@ +package com.vaadin.ui.components.colorpicker; + +import java.io.Serializable; + +import com.vaadin.shared.ui.colorpicker.Color; + +/** + * An interface for a color selector. + * + * @since 7.0.0 + */ +public interface ColorSelector extends Serializable, HasColorChangeListener { + + /** + * Sets the color. + * + * @param color + * the new color + */ + public void setColor(Color color); + + /** + * Gets the color. + * + * @return the color + */ + public Color getColor(); +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/components/colorpicker/HasColorChangeListener.java b/server/src/com/vaadin/ui/components/colorpicker/HasColorChangeListener.java new file mode 100644 index 0000000000..25b3d3c6da --- /dev/null +++ b/server/src/com/vaadin/ui/components/colorpicker/HasColorChangeListener.java @@ -0,0 +1,19 @@ +package com.vaadin.ui.components.colorpicker; + +public interface HasColorChangeListener { + + /** + * Adds a {@link ColorChangeListener} to the component. + * + * @param listener + */ + void addColorChangeListener(ColorChangeListener listener); + + /** + * Removes a {@link ColorChangeListener} from the component. + * + * @param listener + */ + void removeColorChangeListener(ColorChangeListener listener); + +}
\ No newline at end of file diff --git a/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java b/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java index f24638e6a7..250fa3f771 100644 --- a/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java +++ b/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java @@ -50,16 +50,17 @@ public class TestStreamVariableMapping extends TestCase { public void testAddStreamVariable() { String targetUrl = cm.getStreamVariableTargetUrl(owner, variableName, streamVariable); - assertTrue(targetUrl.startsWith("app://APP/UPLOAD/-1/1/myName/")); + assertTrue(targetUrl.startsWith("app://APP/UPLOAD/-1/" + + owner.getConnectorId() + "/myName/")); - ConnectorTracker tracker = UI.getCurrent().getConnectorTracker(); + ConnectorTracker tracker = owner.getUI().getConnectorTracker(); StreamVariable streamVariable2 = tracker.getStreamVariable( owner.getConnectorId(), variableName); assertSame(streamVariable, streamVariable2); } - public void testRemoverVariable() { - ConnectorTracker tracker = UI.getCurrent().getConnectorTracker(); + public void testRemoveVariable() { + ConnectorTracker tracker = owner.getUI().getConnectorTracker(); cm.getStreamVariableTargetUrl(owner, variableName, streamVariable); assertNotNull(tracker.getStreamVariable(owner.getConnectorId(), variableName)); diff --git a/shared/src/com/vaadin/shared/ui/colorpicker/Color.java b/shared/src/com/vaadin/shared/ui/colorpicker/Color.java new file mode 100644 index 0000000000..602821346e --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/colorpicker/Color.java @@ -0,0 +1,378 @@ +package com.vaadin.shared.ui.colorpicker; + +/** + * Default implementation for color. + * + * @since 7.0.0 + */ +public class Color { + + public static final Color WHITE = new Color(255, 255, 255); + public static final Color BLACK = new Color(0, 0, 0); + public static final Color RED = new Color(255, 0, 0); + public static final Color GREEN = new Color(0, 255, 0); + public static final Color BLUE = new Color(0, 0, 255); + public static final Color YELLOW = new Color(255, 255, 0); + public static final Color MAGENTA = new Color(255, 0, 255); + public static final Color CYAN = new Color(0, 255, 255); + + private int red; + private int green; + private int blue; + private int alpha; + + private String OUTOFRANGE = "Value must be within the range [0-255]. Was: "; + + /** + * Creates a color that has the specified red, green, blue, and alpha values + * within the range [0 - 255]. + * + * @throws IllegalArgumentException + * if <code>red</code>, <code>green</code>, <code>blue</code> or + * <code>alpha</code> fall outside of the inclusive range from 0 + * to 255 + * @param red + * the red value + * @param green + * the green value + * @param blue + * the blue value + * @param alpha + * the alpha value + */ + public Color(int red, int green, int blue, int alpha) { + checkRange(red, green, blue, alpha); + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; + } + + /** + * Creates a color that has the specified red, green, and blue values within + * the range [0 - 255]. Alpha gets the default value of 255. + * + * @throws IllegalArgumentException + * if <code>red</code>, <code>green</code> or <code>blue</code> + * fall outside of the inclusive range from 0 to 255 + * @param red + * the red value + * @param green + * the green value + * @param blue + * the blue value + */ + public Color(int red, int green, int blue) { + this(red, green, blue, 255); + } + + /** + * Creates a color based on an RGB value. + * + * @throws IllegalArgumentException + * if converted values of <code>red</code>, <code>green</code>, + * <code>blue</code> or <code>alpha</code> fall outside of the + * inclusive range from 0 to 255 + * + * @param rgb + * the RGB value + */ + public Color(int rgb) { + int value = 0xff000000 | rgb; + int red = (value >> 16) & 0xFF; + int green = (value >> 8) & 0xFF; + int blue = (value >> 0) & 0xFF; + int alpha = (value >> 24) & 0xff; + + checkRange(red, green, blue, alpha); + + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; + } + + /** + * Checks that all values are within the acceptable range of [0, 255]. + * + * @throws IllegalArgumentException + * if any of the values fall outside of the range + * + * @param red + * @param green + * @param blue + * @param alpha + */ + private void checkRange(int red, int green, int blue, int alpha) { + if (!withinRange(red) || !withinRange(green) || !withinRange(blue) + || !withinRange(alpha)) { + + String errorMessage = "All values must fall within range [0-255]. (red: " + + red + + ", green: " + + green + + ", blue: " + + blue + + ", alpha: " + alpha + ")"; + throw new IllegalArgumentException(errorMessage); + } + } + + /** + * Checks whether the value is within the acceptable range of [0, 255]. + * + * @param value + * @return true if the value falls within the range, false otherwise + */ + private boolean withinRange(int value) { + if (value < 0 || value > 255) { + return false; + } + return true; + } + + /** + * Returns the red value of the color. + * + */ + public int getRed() { + return red; + } + + /** + * Sets the red value of the color. Value must be within the range [0, 255]. + * + * @param red + * new red value + */ + public void setRed(int red) { + if (withinRange(red)) { + this.red = red; + } else { + throw new IllegalArgumentException(OUTOFRANGE + red); + } + } + + /** + * Returns the green value of the color. + * + */ + public int getGreen() { + return green; + } + + /** + * Sets the green value of the color. Value must be within the range [0, + * 255]. + * + * @param green + * new green value + */ + public void setGreen(int green) { + if (withinRange(green)) { + this.green = green; + } else { + throw new IllegalArgumentException(OUTOFRANGE + green); + } + } + + /** + * Returns the blue value of the color. + * + */ + public int getBlue() { + return blue; + } + + /** + * Sets the blue value of the color. Value must be within the range [0, + * 255]. + * + * @param blue + * new blue value + */ + public void setBlue(int blue) { + if (withinRange(blue)) { + this.blue = blue; + } else { + throw new IllegalArgumentException(OUTOFRANGE + blue); + } + } + + /** + * Returns the alpha value of the color. + * + */ + public int getAlpha() { + return alpha; + } + + /** + * Sets the alpha value of the color. Value must be within the range [0, + * 255]. + * + * @param alpha + * new alpha value + */ + public void setAlpha(int alpha) { + if (withinRange(alpha)) { + this.alpha = alpha; + } else { + throw new IllegalArgumentException(OUTOFRANGE + alpha); + } + } + + /** + * Returns CSS representation of the Color, e.g. #000000. + */ + public String getCSS() { + String redString = Integer.toHexString(red); + redString = redString.length() < 2 ? "0" + redString : redString; + + String greenString = Integer.toHexString(green); + greenString = greenString.length() < 2 ? "0" + greenString + : greenString; + + String blueString = Integer.toHexString(blue); + blueString = blueString.length() < 2 ? "0" + blueString : blueString; + + return "#" + redString + greenString + blueString; + } + + /** + * Returns RGB value of the color. + */ + public int getRGB() { + return ((alpha & 0xFF) << 24) | ((red & 0xFF) << 16) + | ((green & 0xFF) << 8) | ((blue & 0xFF) << 0); + } + + /** + * Returns converted HSV components of the color. + * + */ + public float[] getHSV() { + float[] hsv = new float[3]; + + int maxColor = (red > green) ? red : green; + if (blue > maxColor) { + maxColor = blue; + } + int minColor = (red < green) ? red : green; + if (blue < minColor) { + minColor = blue; + } + + float value = maxColor / 255.0f; + + float saturation = 0; + if (maxColor != 0) { + saturation = ((float) (maxColor - minColor)) / ((float) maxColor); + } + + float hue = 0; + if (saturation != 0) { + float redF = ((float) (maxColor - red)) + / ((float) (maxColor - minColor)); + float greenF = ((float) (maxColor - green)) + / ((float) (maxColor - minColor)); + float blueF = ((float) (maxColor - blue)) + / ((float) (maxColor - minColor)); + + if (red == maxColor) { + hue = blueF - greenF; + } else if (green == maxColor) { + hue = 2.0f + redF - blueF; + } else { + hue = 4.0f + greenF - redF; + } + + hue = hue / 6.0f; + if (hue < 0) { + hue = hue + 1.0f; + } + } + + hsv[0] = hue; + hsv[1] = saturation; + hsv[2] = value; + return hsv; + } + + @Override + public int hashCode() { + return getRGB(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof Color && ((Color) obj).getRGB() == getRGB(); + } + + /** + * <p> + * Converts HSV's hue, saturation and value into an RGB value. + * <p> + * The <code>saturation</code> and <code>value</code> components should be + * floating-point values within the range [0.0-1.0]. + * <p> + * + * @param hue + * the hue of the color + * @param saturation + * the saturation of the color + * @param value + * the value of the color + * @return the RGB value of corresponding color + */ + public static int HSVtoRGB(float hue, float saturation, float value) { + int red = 0; + int green = 0; + int blue = 0; + + if (saturation == 0) { + red = green = blue = (int) (value * 255.0f + 0.5f); + } else { + float h = (hue - (float) Math.floor(hue)) * 6.0f; + float f = h - (float) java.lang.Math.floor(h); + float p = value * (1.0f - saturation); + float q = value * (1.0f - saturation * f); + float t = value * (1.0f - (saturation * (1.0f - f))); + + switch ((int) h) { + case 0: + red = (int) (value * 255.0f + 0.5f); + green = (int) (t * 255.0f + 0.5f); + blue = (int) (p * 255.0f + 0.5f); + break; + case 1: + red = (int) (q * 255.0f + 0.5f); + green = (int) (value * 255.0f + 0.5f); + blue = (int) (p * 255.0f + 0.5f); + break; + case 2: + red = (int) (p * 255.0f + 0.5f); + green = (int) (value * 255.0f + 0.5f); + blue = (int) (t * 255.0f + 0.5f); + break; + case 3: + red = (int) (p * 255.0f + 0.5f); + green = (int) (q * 255.0f + 0.5f); + blue = (int) (value * 255.0f + 0.5f); + break; + case 4: + red = (int) (t * 255.0f + 0.5f); + green = (int) (p * 255.0f + 0.5f); + blue = (int) (value * 255.0f + 0.5f); + break; + case 5: + red = (int) (value * 255.0f + 0.5f); + green = (int) (p * 255.0f + 0.5f); + blue = (int) (q * 255.0f + 0.5f); + break; + } + } + + return 0xff000000 | (red << 16) | (green << 8) | (blue << 0); + } +} diff --git a/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerGradientServerRpc.java b/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerGradientServerRpc.java new file mode 100644 index 0000000000..e5cf016815 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerGradientServerRpc.java @@ -0,0 +1,21 @@ +package com.vaadin.shared.ui.colorpicker; + +import com.vaadin.shared.communication.ServerRpc; + +/** + * RPC interface for ColorPickerGradient. + * + * @since 7.0.0 + * + */ +public interface ColorPickerGradientServerRpc extends ServerRpc { + + /** + * ColorPickerGradient mouseUp event. + * + * @param cursorX + * @param cursorY + */ + public void select(int cursorX, int cursorY); + +} diff --git a/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerGradientState.java b/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerGradientState.java new file mode 100644 index 0000000000..d8d2a5537d --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerGradientState.java @@ -0,0 +1,18 @@ +package com.vaadin.shared.ui.colorpicker; + +import com.vaadin.shared.AbstractComponentState; + +/** + * Default shared state implementation for ColorPickerGradient. + * + * @since 7.0.0 + */ +public class ColorPickerGradientState extends AbstractComponentState { + + public int cursorX; + + public int cursorY; + + public String bgColor; + +} diff --git a/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerGridServerRpc.java b/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerGridServerRpc.java new file mode 100644 index 0000000000..e56b19c80d --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerGridServerRpc.java @@ -0,0 +1,26 @@ +package com.vaadin.shared.ui.colorpicker; + +import com.vaadin.shared.communication.ServerRpc; + +/** + * RPC interface for ColorPickerGrid. + * + * @since 7.0.0 + * + */ +public interface ColorPickerGridServerRpc extends ServerRpc { + + /** + * ColorPickerGrid click event. + * + * @param x + * @param y + */ + public void select(int x, int y); + + /** + * Call to refresh the grid. + */ + public void refresh(); + +} diff --git a/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerGridState.java b/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerGridState.java new file mode 100644 index 0000000000..e79a3c2b88 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerGridState.java @@ -0,0 +1,22 @@ +package com.vaadin.shared.ui.colorpicker; + +import com.vaadin.shared.AbstractComponentState; + +/** + * Default shared state implementation for ColorPickerGrid. + * + * @since 7.0.0 + */ +public class ColorPickerGridState extends AbstractComponentState { + + public int rowCount; + + public int columnCount; + + public String[] changedX; + + public String[] changedY; + + public String[] changedColor; + +} diff --git a/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerServerRpc.java b/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerServerRpc.java new file mode 100644 index 0000000000..7269923c83 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerServerRpc.java @@ -0,0 +1,21 @@ +package com.vaadin.shared.ui.colorpicker; + +import com.vaadin.shared.communication.ServerRpc; + +/** + * RPC interface for AbstractColorPicker. + * + * @since 7.0.0 + * + */ +public interface ColorPickerServerRpc extends ServerRpc { + + /** + * ColorPicker click event. + * + * @param openPopup + * + */ + public void openPopup(boolean openPopup); + +} diff --git a/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerState.java b/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerState.java new file mode 100644 index 0000000000..1a914cfaa4 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/colorpicker/ColorPickerState.java @@ -0,0 +1,25 @@ +package com.vaadin.shared.ui.colorpicker; + +import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.annotations.DelegateToWidget; + +/** + * Default shared state implementation for AbstractColorPicker. + * + * @since 7.0.0 + */ +public class ColorPickerState extends AbstractComponentState { + { + primaryStyleName = "v-colorpicker"; + } + + @DelegateToWidget("setOpen") + public boolean popupVisible = false; + + @DelegateToWidget("setColor") + public String color = null; + + public boolean showDefaultCaption; + + public boolean htmlContentAllowed; +} diff --git a/theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml b/theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml index 495b6d00c9..f921bec167 100644 --- a/theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml +++ b/theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml @@ -32,7 +32,7 @@ <dependency org="args4j" name="args4j" rev="2.0.9" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/> <dependency org="commons-math" name="commons-math" rev="1.1" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/> <dependency org="commons-io" name="commons-io" rev="1.4" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/> - <dependency org="commons-lang" name="commons-lang" rev="2.3" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/> + <dependency org="commons-lang" name="commons-lang" rev="2.6" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/> <dependency org="junit" name="junit" rev="4.4" force="true" conf="test->runtime(*),master(*)"/> </dependencies> </ivy-module> diff --git a/uitest/src/com/vaadin/tests/components/colorpicker/ColorPickerTest.html b/uitest/src/com/vaadin/tests/components/colorpicker/ColorPickerTest.html new file mode 100644 index 0000000000..fb8669b9f0 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/colorpicker/ColorPickerTest.html @@ -0,0 +1,339 @@ +<?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="http://localhost:8888/run/com.vaadin.tests.components.colorpicker.ColorPickerTest?restartApplication" /> +<title>ColorPickerTest</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">ColorPickerTest</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.colorpicker.ColorPickerTest?restartApplication</td> + <td></td> +</tr> + +<!-- change foreground color --> +<tr> + <td>click</td> + <td>colorpicker1</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_Srgb-gradient/domChild[1]/domChild[4]</td> + <td>190,87</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[3]/VHorizontalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> + +<!-- change background color --> +<tr> + <td>click</td> + <td>colorpicker2</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_Srgb-gradient/domChild[1]/domChild[4]</td> + <td>51,33</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[3]/VHorizontalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>pink-on-yellow</td> +</tr> + +<!-- change foreground color with area button --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_Scolorpicker5/domChild[1]</td> + <td>10,15</td> +</tr> +<!-- expand history --> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[2]/VButton[0]/domChild[0]</td> + <td></td> +</tr> +<!-- choose from history --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VCustomComponent[0]/VColorPickerGrid[0]/domChild[0]/domChild[1]/domChild[0]/domChild[3]</td> + <td>9,9</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[3]/VHorizontalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> + +<!-- change background color with area button --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_Scolorpicker6/domChild[1]</td> + <td>12,24</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VCustomComponent[0]/VColorPickerGrid[0]/domChild[0]/domChild[1]/domChild[0]/domChild[1]</td> + <td>9,12</td> +</tr> +<!-- choose from history --> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[3]/VHorizontalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>black-on-white</td> +</tr> + +<!-- open and close --> +<tr> + <td>click</td> + <td>colorpicker1</td> + <td></td> +</tr> +<tr> + <td>click</td> + <td>colorpicker1</td> + <td></td> +</tr> + +<!-- open and close using area button --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_Scolorpicker5/domChild[1]</td> + <td>11,17</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_Scolorpicker5/domChild[1]</td> + <td>11,17</td> +</tr> + +<!-- open background (using area button) to display HSV effects --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_Scolorpicker6/domChild[1]</td> + <td>21,15</td> +</tr> +<!-- HSV tab --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]</td> + <td>12,6</td> +</tr> +<!-- hue slider --> +<tr> + <td>dragAndDrop</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[2]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VSlider[0]/domChild[2]/domChild[0]</td> + <td>136,0</td> +</tr> +<!-- saturation slider --> +<tr> + <td>dragAndDrop</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[2]/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VSlider[0]/domChild[2]/domChild[0]</td> + <td>100,0</td> +</tr> +<!-- value slider --> +<tr> + <td>dragAndDrop</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[2]/VVerticalLayout[0]/VOrderedLayout$Slot[2]/VSlider[0]/domChild[2]/domChild[0]</td> + <td>-60,0</td> +</tr> +<!-- Swatches tab (choose color) --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]/domChild[0]/domChild[0]/domChild[0]</td> + <td>43,8</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VCustomComponent[0]/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VColorPickerGrid[0]/domChild[0]/domChild[1]/domChild[11]/domChild[9]</td> + <td>12,10</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[3]/VHorizontalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>black-on-purple</td> +</tr> + +<!-- open foreground (using area button) to display checkbox effects --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_Scolorpicker5/domChild[1]</td> + <td>14,25</td> +</tr> +<!-- remove Swatches tab --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_SswaBox/domChild[0]</td> + <td>9,6</td> +</tr> +<!-- remove css field --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_StxtBox/domChild[0]</td> + <td>6,9</td> +</tr> +<!-- remove history --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_ShisBox/domChild[0]</td> + <td>6,7</td> +</tr> +<!-- remove RGB tab --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_SrgbBox/domChild[0]</td> + <td>6,7</td> +</tr> +<!-- return RGB tab --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_SrgbBox/domChild[0]</td> + <td>6,7</td> +</tr> +<!-- remove HSV tab --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_ShsvBox/domChild[0]</td> + <td>6,9</td> +</tr> +<!-- return HSV tab --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_ShsvBox/domChild[0]</td> + <td>6,9</td> +</tr> +<!-- return css field --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_StxtBox/domChild[0]</td> + <td>8,8</td> +</tr> +<!-- return history --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_ShisBox/domChild[0]</td> + <td>6,8</td> +</tr> +<!-- return Swatches tab --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_SswaBox/domChild[0]</td> + <td>4,8</td> +</tr> +<!-- close without choosing a new color --> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[3]/VHorizontalLayout[0]/VOrderedLayout$Slot[1]/VButton[0]/domChild[0]</td> + <td></td> +</tr> + +<!-- change color of the first shade button --> +<tr> + <td>click</td> + <td>shadebutton_1</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_Srgb-gradient/domChild[1]/domChild[4]</td> + <td>148,127</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[3]/VHorizontalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>blue-first-button</td> +</tr> + +<!-- reset the color back to black --> +<tr> + <td>click</td> + <td>shadebutton_1</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VCustomComponent[0]/VColorPickerGrid[0]/domChild[0]/domChild[1]/domChild[0]/domChild[6]</td> + <td>10,7</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[3]/VHorizontalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> + +<!-- change color of the last shade area --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_Sshadearea_16/domChild[1]</td> + <td>10,-65</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_Srgb-gradient/domChild[1]/domChild[4]</td> + <td>36,93</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[3]/VHorizontalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>yellow-last-area</td> +</tr> + +<!-- reset the color back to white --> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::PID_Sshadearea_16/domChild[1]</td> + <td>19,-65</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VCustomComponent[0]/VColorPickerGrid[0]/domChild[0]/domChild[1]/domChild[0]/domChild[4]</td> + <td>6,7</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscolorpickerColorPickerTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/VOrderedLayout$Slot[3]/VHorizontalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>final</td> +</tr> +</tbody></table> +</body> +</html> diff --git a/uitest/src/com/vaadin/tests/components/colorpicker/ColorPickerTest.java b/uitest/src/com/vaadin/tests/components/colorpicker/ColorPickerTest.java new file mode 100644 index 0000000000..0f7e639725 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/colorpicker/ColorPickerTest.java @@ -0,0 +1,492 @@ +package com.vaadin.tests.components.colorpicker; + +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.Date; + +import javax.imageio.ImageIO; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.server.StreamResource; +import com.vaadin.shared.ui.colorpicker.Color; +import com.vaadin.shared.ui.label.ContentMode; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.AbstractColorPicker; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.ColorPicker; +import com.vaadin.ui.ColorPickerArea; +import com.vaadin.ui.Embedded; +import com.vaadin.ui.GridLayout; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.Panel; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.components.colorpicker.ColorChangeEvent; +import com.vaadin.ui.components.colorpicker.ColorChangeListener; + +public class ColorPickerTest extends TestBase implements ColorChangeListener { + + @Override + protected String getDescription() { + return "Vaadin 7 compatible ColorPicker"; + } + + @Override + protected Integer getTicketNumber() { + return 9201; + } + + /** The foreground color. */ + private Color foregroundColor = Color.BLACK; // The currently selected + + /** The background color. */ + private Color backgroundColor = Color.WHITE; // The currently selected + + // The display box where the image is rendered + /** The display. */ + private Embedded display; + + private AbstractColorPicker colorpicker1; + private AbstractColorPicker colorpicker2; + private AbstractColorPicker colorpicker3; + private AbstractColorPicker colorpicker4; + private AbstractColorPicker colorpicker5; + private AbstractColorPicker colorpicker6; + + private boolean rgbVisible = true; + private boolean hsvVisible = true; + private boolean swaVisible = true; + private boolean historyVisible = true; + private boolean txtfieldVisible = true; + + private final CheckBox rgbBox = new CheckBox("RGB tab visible"); + private final CheckBox hsvBox = new CheckBox("HSV tab visible"); + private final CheckBox swaBox = new CheckBox("Swatches tab visible"); + private final CheckBox hisBox = new CheckBox("History visible"); + private final CheckBox txtBox = new CheckBox("CSS field visible"); + + /** + * This class is used to represent the preview of the color selection. + */ + public class MyImageSource implements StreamResource.StreamSource { + + /** The imagebuffer. */ + private java.io.ByteArrayOutputStream imagebuffer = null; + + /** The bg color. */ + private final java.awt.Color bgColor; + + /** The fg color. */ + private final java.awt.Color fgColor; + + /** + * Instantiates a new my image source. + * + * @param fg + * the foreground + * @param bg + * the background + */ + public MyImageSource(java.awt.Color fg, java.awt.Color bg) { + fgColor = fg; + bgColor = bg; + } + + /* Must implement this method that returns the resource as a stream. */ + @Override + public InputStream getStream() { + + /* Create an image and draw something on it. */ + BufferedImage image = new BufferedImage(270, 270, + BufferedImage.TYPE_INT_RGB); + Graphics drawable = image.getGraphics(); + drawable.setColor(bgColor); + drawable.fillRect(0, 0, 270, 270); + drawable.setColor(fgColor); + drawable.fillOval(25, 25, 220, 220); + drawable.setColor(java.awt.Color.blue); + drawable.drawRect(0, 0, 269, 269); + drawable.setColor(java.awt.Color.black); + drawable.drawString( + "r=" + String.valueOf(fgColor.getRed()) + ",g=" + + String.valueOf(fgColor.getGreen()) + ",b=" + + String.valueOf(fgColor.getBlue()), 50, 100); + drawable.drawString( + "r=" + String.valueOf(bgColor.getRed()) + ",g=" + + String.valueOf(bgColor.getGreen()) + ",b=" + + String.valueOf(bgColor.getBlue()), 5, 15); + + try { + /* Write the image to a buffer. */ + imagebuffer = new ByteArrayOutputStream(); + ImageIO.write(image, "png", imagebuffer); + + /* Return a stream from the buffer. */ + return new ByteArrayInputStream(imagebuffer.toByteArray()); + } catch (IOException e) { + return null; + } + } + } + + private void setPopupVisibilities() { + + rgbBox.setEnabled(!(rgbVisible && !hsvVisible && !swaVisible)); + hsvBox.setEnabled(!(!rgbVisible && hsvVisible && !swaVisible)); + swaBox.setEnabled(!(!rgbVisible && !hsvVisible && swaVisible)); + + colorpicker1.setRGBVisibility(rgbVisible); + colorpicker2.setRGBVisibility(rgbVisible); + colorpicker3.setRGBVisibility(rgbVisible); + colorpicker4.setRGBVisibility(rgbVisible); + colorpicker5.setRGBVisibility(rgbVisible); + colorpicker6.setRGBVisibility(rgbVisible); + + colorpicker1.setHSVVisibility(hsvVisible); + colorpicker2.setHSVVisibility(hsvVisible); + colorpicker3.setHSVVisibility(hsvVisible); + colorpicker4.setHSVVisibility(hsvVisible); + colorpicker5.setHSVVisibility(hsvVisible); + colorpicker6.setHSVVisibility(hsvVisible); + + colorpicker1.setSwatchesVisibility(swaVisible); + colorpicker2.setSwatchesVisibility(swaVisible); + colorpicker3.setSwatchesVisibility(swaVisible); + colorpicker4.setSwatchesVisibility(swaVisible); + colorpicker5.setSwatchesVisibility(swaVisible); + colorpicker6.setSwatchesVisibility(swaVisible); + + colorpicker1.setHistoryVisibility(historyVisible); + colorpicker2.setHistoryVisibility(historyVisible); + colorpicker3.setHistoryVisibility(historyVisible); + colorpicker4.setHistoryVisibility(historyVisible); + colorpicker5.setHistoryVisibility(historyVisible); + colorpicker6.setHistoryVisibility(historyVisible); + + colorpicker1.setTextfieldVisibility(txtfieldVisible); + colorpicker2.setTextfieldVisibility(txtfieldVisible); + colorpicker3.setTextfieldVisibility(txtfieldVisible); + colorpicker4.setTextfieldVisibility(txtfieldVisible); + colorpicker5.setTextfieldVisibility(txtfieldVisible); + colorpicker6.setTextfieldVisibility(txtfieldVisible); + } + + @Override + protected void setup() { + getLayout().setWidth("1000px"); + getLayout().setHeight(null); + getLayout().addStyleName("colorpicker-mainwindow-content"); + + // Create an instance of the preview and add it to the window + display = new Embedded("Color preview"); + display.setWidth("270px"); + display.setHeight("270px"); + + // Add the foreground and background colorpickers to a layout + HorizontalLayout mainLayout = new HorizontalLayout(); + mainLayout.addStyleName("colorpicker-mainlayout"); + mainLayout.setWidth("100%"); + mainLayout.setHeight(null); + mainLayout.setMargin(true); + mainLayout.setSpacing(true); + getLayout().addComponent(mainLayout); + + VerticalLayout layoutLeft = new VerticalLayout(); + layoutLeft.setWidth("450px"); + layoutLeft.setHeight(null); + layoutLeft.setSpacing(true); + + GridLayout optLayout = new GridLayout(3, 2); + optLayout.setWidth("100%"); + optLayout.setHeight(null); + optLayout.setMargin(true); + optLayout.setSpacing(true); + + rgbBox.setValue(rgbVisible); + rgbBox.addValueChangeListener(new CheckBox.ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + rgbVisible = (Boolean) event.getProperty().getValue(); + setPopupVisibilities(); + } + }); + rgbBox.setImmediate(true); + rgbBox.setId("rgbBox"); + optLayout.addComponent(rgbBox); + + hsvBox.setValue(hsvVisible); + hsvBox.addValueChangeListener(new CheckBox.ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + hsvVisible = (Boolean) event.getProperty().getValue(); + setPopupVisibilities(); + } + }); + hsvBox.setImmediate(true); + hsvBox.setId("hsvBox"); + optLayout.addComponent(hsvBox); + + swaBox.setValue(swaVisible); + swaBox.addValueChangeListener(new CheckBox.ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + swaVisible = (Boolean) event.getProperty().getValue(); + setPopupVisibilities(); + } + }); + swaBox.setImmediate(true); + swaBox.setId("swaBox"); + optLayout.addComponent(swaBox); + + hisBox.setValue(historyVisible); + hisBox.addValueChangeListener(new CheckBox.ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + historyVisible = (Boolean) event.getProperty().getValue(); + setPopupVisibilities(); + } + }); + hisBox.setImmediate(true); + hisBox.setId("hisBox"); + optLayout.addComponent(hisBox); + + txtBox.setValue(txtfieldVisible); + txtBox.addValueChangeListener(new CheckBox.ValueChangeListener() { + @Override + public void valueChange(ValueChangeEvent event) { + txtfieldVisible = (Boolean) event.getProperty().getValue(); + setPopupVisibilities(); + } + }); + txtBox.setImmediate(true); + txtBox.setId("txtBox"); + optLayout.addComponent(txtBox); + + Panel optPanel = new Panel("Customize the color picker popup window", + optLayout); + layoutLeft.addComponent(optPanel); + + HorizontalLayout layout1 = createHorizontalLayout(); + + colorpicker1 = new ColorPicker("Foreground", foregroundColor); + colorpicker1.setHtmlContentAllowed(true); + colorpicker1.addColorChangeListener(this); + colorpicker1.setId("colorpicker1"); + layout1.addComponent(colorpicker1); + layout1.setComponentAlignment(colorpicker1, Alignment.MIDDLE_CENTER); + + colorpicker2 = new ColorPicker("Background", backgroundColor); + colorpicker2.addColorChangeListener(this); + colorpicker2.setId("colorpicker2"); + layout1.addComponent(colorpicker2); + layout1.setComponentAlignment(colorpicker2, Alignment.MIDDLE_CENTER); + + Panel panel1 = new Panel( + "Button-like colorpicker with current color and CSS code", + layout1); + layoutLeft.addComponent(panel1); + + HorizontalLayout layout2 = createHorizontalLayout(); + + colorpicker3 = new ColorPicker("Foreground", foregroundColor); + colorpicker3.addColorChangeListener(this); + colorpicker3.setWidth("120px"); + colorpicker3.setCaption("Foreground"); + colorpicker3.setId("colorpicker3"); + layout2.addComponent(colorpicker3); + layout2.setComponentAlignment(colorpicker3, Alignment.MIDDLE_CENTER); + + colorpicker4 = new ColorPicker("Background", backgroundColor); + colorpicker4.addColorChangeListener(this); + colorpicker4.setWidth("120px"); + colorpicker4.setCaption("Background"); + colorpicker4.setId("colorpicker4"); + layout2.addComponent(colorpicker4); + layout2.setComponentAlignment(colorpicker4, Alignment.MIDDLE_CENTER); + + Panel panel2 = new Panel( + "Button-like colorpicker with current color and custom caption", + layout2); + layoutLeft.addComponent(panel2); + + HorizontalLayout layout3 = createHorizontalLayout(); + + colorpicker5 = new ColorPickerArea("Foreground", foregroundColor); + colorpicker5.setCaption("Foreground"); + colorpicker5.addColorChangeListener(this); + colorpicker5.setId("colorpicker5"); + layout3.addComponent(colorpicker5); + layout3.setComponentAlignment(colorpicker5, Alignment.MIDDLE_CENTER); + + colorpicker6 = new ColorPickerArea("Background", backgroundColor); + colorpicker6.setCaption("Background"); + colorpicker6.setDefaultCaptionEnabled(false); + colorpicker6.addColorChangeListener(this); + colorpicker6.setId("colorpicker6"); + layout3.addComponent(colorpicker6); + layout3.setComponentAlignment(colorpicker6, Alignment.MIDDLE_CENTER); + + Panel panel3 = new Panel("Color area colorpicker with caption", layout3); + panel3.setWidth("100%"); + panel3.setHeight(null); + layoutLeft.addComponent(panel3); + + Label divider1 = new Label("<hr>", ContentMode.HTML); + layoutLeft.addComponent(divider1); + + Label divider2 = new Label("<hr>", ContentMode.HTML); + layoutLeft.addComponent(divider2); + + HorizontalLayout layout4 = createHorizontalLayout(); + + addShadeButton(new Color(Integer.parseInt("000000", 16)), layout4); + addShadeButton(new Color(Integer.parseInt("333333", 16)), layout4); + addShadeButton(new Color(Integer.parseInt("666666", 16)), layout4); + addShadeButton(new Color(Integer.parseInt("999999", 16)), layout4); + addShadeButton(new Color(Integer.parseInt("cccccc", 16)), layout4); + addShadeButton(new Color(Integer.parseInt("ffffff", 16)), layout4); + + Panel panel4 = new Panel( + "Button-like colorpickers with disabled caption (no effect on fg/bg colors)", + layout4); + layoutLeft.addComponent(panel4); + + HorizontalLayout layout5 = createHorizontalLayout(); + + addShadeArea(new Color(Integer.parseInt("000000", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("111111", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("222222", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("333333", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("444444", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("555555", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("666666", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("777777", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("888888", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("999999", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("aaaaaa", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("bbbbbb", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("cccccc", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("dddddd", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("eeeeee", 16)), layout5); + addShadeArea(new Color(Integer.parseInt("ffffff", 16)), layout5); + + Panel panel5 = new Panel( + "Area colorpickers with no given caption (no effect on fg/bg colors)", + layout5); + layoutLeft.addComponent(panel5); + + mainLayout.addComponent(layoutLeft); + + mainLayout.addComponent(display); + + updateDisplay(foregroundColor, backgroundColor); + } + + private HorizontalLayout createHorizontalLayout() { + HorizontalLayout layout = new HorizontalLayout(); + layout.setWidth("100%"); + layout.setHeight(null); + layout.setMargin(true); + return layout; + } + + private int shadeButtonCounter = 1; + + private void addShadeButton(Color color, HorizontalLayout layout) { + AbstractColorPicker colorPicker = new ColorPicker(color.toString(), + color); + colorPicker.setDefaultCaptionEnabled(false); + colorPicker.setWidth("41px"); + colorPicker.setId("shadebutton_" + shadeButtonCounter); + layout.addComponent(colorPicker); + layout.setComponentAlignment(colorPicker, Alignment.MIDDLE_CENTER); + + ++shadeButtonCounter; + } + + private int shadeAreaCounter = 1; + + private void addShadeArea(Color color, HorizontalLayout layout) { + AbstractColorPicker colorPicker = new ColorPickerArea(color.toString(), + color); + colorPicker.setWidth("20px"); + colorPicker.setHeight("20px"); + colorPicker.setId("shadearea_" + shadeAreaCounter); + layout.addComponent(colorPicker); + layout.setComponentAlignment(colorPicker, Alignment.MIDDLE_CENTER); + + ++shadeAreaCounter; + } + + // This is called whenever a colorpicker popup is closed + /** + * Update display. + * + * @param fg + * the fg + * @param bg + * the bg + */ + public void updateDisplay(Color fg, Color bg) { + java.awt.Color awtFg = new java.awt.Color(fg.getRed(), fg.getGreen(), + fg.getBlue()); + java.awt.Color awtBg = new java.awt.Color(bg.getRed(), bg.getGreen(), + bg.getBlue()); + StreamResource.StreamSource imagesource = new MyImageSource(awtFg, + awtBg); + + Date now = new Date(); + SimpleDateFormat format = new SimpleDateFormat("hhmmss"); + + StreamResource imageresource = new StreamResource(imagesource, + "myimage" + format.format(now) + ".png"); + imageresource.setCacheTime(0); + + display.setSource(imageresource); + } + + @Override + public void colorChanged(ColorChangeEvent event) { + if (event.getSource() == colorpicker1 + || event.getSource() == colorpicker3 + || event.getSource() == colorpicker5) { + foregroundColor = event.getColor(); + + if (event.getSource() != colorpicker1) { + colorpicker1.setColor(event.getColor()); + } + if (event.getSource() != colorpicker3) { + colorpicker3.setColor(event.getColor()); + } + if (event.getSource() != colorpicker5) { + colorpicker5.setColor(event.getColor()); + } + + } else if (event.getSource() == colorpicker2 + || event.getSource() == colorpicker4 + || event.getSource() == colorpicker6) { + backgroundColor = event.getColor(); + + if (event.getSource() != colorpicker2) { + colorpicker2.setColor(event.getColor()); + } + if (event.getSource() != colorpicker4) { + colorpicker4.setColor(event.getColor()); + } + if (event.getSource() != colorpicker6) { + colorpicker6.setColor(event.getColor()); + } + + } else { + return; + } + + updateDisplay(foregroundColor, backgroundColor); + } +} diff --git a/uitest/src/com/vaadin/tests/components/customfield/AddressField.java b/uitest/src/com/vaadin/tests/components/customfield/AddressField.java index 2daeb7bf25..595a2e2cde 100644 --- a/uitest/src/com/vaadin/tests/components/customfield/AddressField.java +++ b/uitest/src/com/vaadin/tests/components/customfield/AddressField.java @@ -38,7 +38,7 @@ public class AddressField extends CustomField<Address> { // make sure field changes are sent early addressForm.setImmediate(true); - + addressForm.setFooter(null); return addressForm; } diff --git a/uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html b/uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html index 3c2d97ec17..e764d62b12 100644 --- a/uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html +++ b/uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html @@ -129,7 +129,7 @@ <tr> <td>screenCapture</td> <td></td> - <td>selects-first-popup</td> + <td>selects-first-open</td> </tr> <tr> <td>mouseClick</td> @@ -139,7 +139,7 @@ <tr> <td>screenCapture</td> <td></td> - <td>selects-second-popup</td> + <td>selects-second-open</td> </tr> <tr> <td>mouseClick</td> @@ -149,7 +149,7 @@ <tr> <td>screenCapture</td> <td></td> - <td>selects-third-popup</td> + <td>selects-third-open</td> </tr> <tr> <td>mouseClick</td> @@ -159,7 +159,7 @@ <tr> <td>screenCapture</td> <td></td> - <td>selects-fourth-popup</td> + <td>selects-fourth-open</td> </tr> <tr> <td>mouseClick</td> |