import java.util.ArrayList;\r
import java.util.Iterator;\r
\r
+import com.google.gwt.dom.client.Style.Overflow;\r
import com.google.gwt.event.dom.client.ClickEvent;\r
import com.google.gwt.event.dom.client.DoubleClickEvent;\r
import com.google.gwt.event.dom.client.DoubleClickHandler;\r
import com.google.gwt.user.client.ui.HTML;\r
import com.google.gwt.user.client.ui.ListBox;\r
import com.google.gwt.user.client.ui.Panel;\r
+import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
import com.vaadin.terminal.gwt.client.UIDL;\r
+import com.vaadin.terminal.gwt.client.Util;\r
\r
public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler,\r
MouseDownHandler, DoubleClickHandler {\r
\r
private static final String CLASSNAME = "v-select-twincol";\r
+ public static final String ATTRIBUTE_LEFT_CAPTION = "lc";\r
+ public static final String ATTRIBUTE_RIGHT_CAPTION = "rc";\r
\r
private static final int VISIBLE_COUNT = 10;\r
\r
\r
private final DoubleClickListBox selections;\r
\r
+ private FlowPanel captionWrapper;\r
+\r
+ private HTML optionsCaption = null;\r
+\r
+ private HTML selectionsCaption = null;\r
+\r
private final VButton add;\r
\r
private final VButton remove;\r
super();\r
}\r
\r
+ @Override\r
public HandlerRegistration addDoubleClickHandler(\r
DoubleClickHandler handler) {\r
return addDomHandler(handler, DoubleClickEvent.getType());\r
\r
public VTwinColSelect() {\r
super(CLASSNAME);\r
+\r
+ captionWrapper = new FlowPanel();\r
+\r
options = new DoubleClickListBox();\r
options.addClickHandler(this);\r
options.addDoubleClickHandler(this);\r
+ options.setVisibleItemCount(VISIBLE_COUNT);\r
+ options.setStyleName(CLASSNAME + "-options");\r
+\r
selections = new DoubleClickListBox();\r
selections.addClickHandler(this);\r
selections.addDoubleClickHandler(this);\r
- options.setVisibleItemCount(VISIBLE_COUNT);\r
selections.setVisibleItemCount(VISIBLE_COUNT);\r
- options.setStyleName(CLASSNAME + "-options");\r
selections.setStyleName(CLASSNAME + "-selections");\r
+\r
buttons = new FlowPanel();\r
buttons.setStyleName(CLASSNAME + "-buttons");\r
add = new VButton();\r
remove = new VButton();\r
remove.setText("<<");\r
remove.addClickHandler(this);\r
+\r
panel = ((Panel) optionsContainer);\r
+\r
+ panel.add(captionWrapper);\r
+ captionWrapper.getElement().getStyle().setOverflow(Overflow.HIDDEN);\r
+ // Hide until there actually is a caption to prevent IE from rendering\r
+ // extra empty space\r
+ captionWrapper.setVisible(false);\r
+\r
panel.add(options);\r
buttons.add(add);\r
final HTML br = new HTML("<span/>");\r
selections.addKeyDownHandler(this);\r
}\r
\r
+ public HTML getOptionsCaption() {\r
+ if (optionsCaption == null) {\r
+ optionsCaption = new HTML();\r
+ optionsCaption.setStyleName(CLASSNAME + "-options-caption");\r
+ optionsCaption.getElement().getStyle()\r
+ .setFloat(com.google.gwt.dom.client.Style.Float.LEFT);\r
+ captionWrapper.add(optionsCaption);\r
+ }\r
+\r
+ return optionsCaption;\r
+ }\r
+\r
+ public HTML getSelectionsCaption() {\r
+ if (selectionsCaption == null) {\r
+ selectionsCaption = new HTML();\r
+ selectionsCaption.setStyleName(CLASSNAME + "-selections-caption");\r
+ selectionsCaption.getElement().getStyle()\r
+ .setFloat(com.google.gwt.dom.client.Style.Float.RIGHT);\r
+ captionWrapper.add(selectionsCaption);\r
+ }\r
+\r
+ return selectionsCaption;\r
+ }\r
+\r
+ @Override\r
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+ // Captions are updated before super call to ensure the widths are set\r
+ // correctly\r
+ updateCaptions(uidl);\r
+\r
+ super.updateFromUIDL(uidl, client);\r
+ // If the server request that a cached instance should be used, do\r
+ // nothing\r
+ // if (uidl.isCachedComponent()) {\r
+ if (uidl.getBooleanAttribute("cached")) {\r
+ // Cached update, nothing to do)\r
+ return;\r
+ }\r
+\r
+ }\r
+\r
+ private void updateCaptions(UIDL uidl) {\r
+ String leftCaption = (uidl.hasAttribute(ATTRIBUTE_LEFT_CAPTION) ? uidl\r
+ .getStringAttribute(ATTRIBUTE_LEFT_CAPTION) : null);\r
+ String rightCaption = (uidl.hasAttribute(ATTRIBUTE_RIGHT_CAPTION) ? uidl\r
+ .getStringAttribute(ATTRIBUTE_RIGHT_CAPTION) : null);\r
+\r
+ boolean hasCaptions = (leftCaption != null || rightCaption != null);\r
+\r
+ if (leftCaption == null) {\r
+ removeOptionsCaption();\r
+ } else {\r
+ getOptionsCaption().setText(leftCaption);\r
+\r
+ }\r
+\r
+ if (rightCaption == null) {\r
+ removeSelectionsCaption();\r
+ } else {\r
+ getSelectionsCaption().setText(rightCaption);\r
+ }\r
+\r
+ captionWrapper.setVisible(hasCaptions);\r
+ }\r
+\r
+ private void removeOptionsCaption() {\r
+ if (optionsCaption == null) {\r
+ return;\r
+ }\r
+\r
+ if (optionsCaption.getParent() != null) {\r
+ captionWrapper.remove(optionsCaption);\r
+ }\r
+\r
+ optionsCaption = null;\r
+ }\r
+\r
+ private void removeSelectionsCaption() {\r
+ if (selectionsCaption == null) {\r
+ return;\r
+ }\r
+\r
+ if (selectionsCaption.getParent() != null) {\r
+ captionWrapper.remove(selectionsCaption);\r
+ }\r
+\r
+ selectionsCaption = null;\r
+ }\r
+\r
@Override\r
protected void buildOptions(UIDL uidl) {\r
final boolean enabled = !isDisabled() && !isReadonly();\r
}\r
\r
if (cols >= 0) {\r
- options.setWidth(cols + "em");\r
- selections.setWidth(cols + "em");\r
+ String colWidth = cols + "em";\r
+ String containerWidth = (2 * cols + 4) + "em";\r
+ // Caption wrapper width == optionsSelect + buttons +\r
+ // selectionsSelect\r
+ String captionWrapperWidth = (2 * cols + 4 - 0.5) + "em";\r
+\r
+ options.setWidth(colWidth);\r
+ if (optionsCaption != null) {\r
+ optionsCaption.setWidth(colWidth);\r
+ }\r
+ selections.setWidth(colWidth);\r
+ if (selectionsCaption != null) {\r
+ selectionsCaption.setWidth(colWidth);\r
+ }\r
buttons.setWidth("3.5em");\r
- optionsContainer.setWidth((2 * cols + 4) + "em");\r
+ optionsContainer.setWidth(containerWidth);\r
+ captionWrapper.setWidth(captionWrapperWidth);\r
}\r
if (getRows() > 0) {\r
options.setVisibleItemCount(getRows());\r
options.setHeight("");\r
selections.setHeight("");\r
} else {\r
- setFullHeightInternals();\r
+ setInternalHeights();\r
}\r
}\r
\r
- private void setFullHeightInternals() {\r
- options.setHeight("100%");\r
- selections.setHeight("100%");\r
+ private void setInternalHeights() {\r
+ int captionHeight = 0;\r
+ int totalHeight = getOffsetHeight();\r
+\r
+ if (optionsCaption != null) {\r
+ captionHeight = Util.getRequiredHeight(optionsCaption);\r
+ } else if (selectionsCaption != null) {\r
+ captionHeight = Util.getRequiredHeight(selectionsCaption);\r
+ }\r
+ String selectHeight = (totalHeight - captionHeight) + "px";\r
+\r
+ selections.setHeight(selectHeight);\r
+ options.setHeight(selectHeight);\r
+\r
}\r
\r
@Override\r
public void setWidth(String width) {\r
super.setWidth(width);\r
if (!"".equals(width) && width != null) {\r
- setRelativeInternalWidths();\r
+ setInternalWidths();\r
+ widthSet = true;\r
+ } else {\r
+ widthSet = false;\r
}\r
}\r
\r
- private void setRelativeInternalWidths() {\r
+ private void setInternalWidths() {\r
DOM.setStyleAttribute(getElement(), "position", "relative");\r
- buttons.setWidth("15%");\r
- options.setWidth("42%");\r
- selections.setWidth("42%");\r
- widthSet = true;\r
+ // TODO: Should really take borders/padding/margin into account.\r
+ // Compensating for now with a guess.\r
+ int buttonsExtraWidthGuess = 4;\r
+ int buttonWidth = Util.getRequiredWidth(buttons)\r
+ + buttonsExtraWidthGuess;\r
+ int totalWidth = getOffsetWidth();\r
+\r
+ int spaceForSelect = (totalWidth - buttonWidth) / 2;\r
+\r
+ options.setWidth(spaceForSelect + "px");\r
+ if (optionsCaption != null) {\r
+ optionsCaption.setWidth(spaceForSelect + "px");\r
+ }\r
+\r
+ selections.setWidth(spaceForSelect + "px");\r
+ if (selectionsCaption != null) {\r
+ selectionsCaption.setWidth(spaceForSelect + "px");\r
+ }\r
+ captionWrapper.setWidth("100%");\r
}\r
\r
@Override\r
private int columns = 0;
private int rows = 0;
+ private String leftColumnCaption;
+ private String rightColumnCaption;
+
/**
*
*/
* Sets the number of columns in the editor. If the number of columns is set
* 0, the actual number of displayed columns is determined implicitly by the
* adapter.
+ * <p>
+ * The number of columns overrides the value set by setWidth. Only if
+ * columns are set to 0 (default) the width set using
+ * {@link #setWidth(float, int)} or {@link #setWidth(String)} is used.
*
* @param columns
* the number of columns to set.
}
/**
- * Sets the number of rows in the editor. If the number of rows is set 0,
+ * Sets the number of rows in the editor. If the number of rows is set to 0,
* the actual number of displayed rows is determined implicitly by the
* adapter.
+ * <p>
+ * If a height if set (using {@link #setHeight(String)} or
+ * {@link #setHeight(float, int)}) it overrides the number of rows. Leave
+ * the height undefined to use this method. This is the opposite of how
+ * {@link #setColumns(int)} work.
+ *
*
* @param rows
* the number of rows to set.
if (rows != 0) {
target.addAttribute("rows", rows);
}
+
+ // Right and left column captions and/or icons (if set)
+ String lc = getLeftColumnCaption();
+ String rc = getRightColumnCaption();
+ if (lc != null) {
+ target.addAttribute(VTwinColSelect.ATTRIBUTE_LEFT_CAPTION, lc);
+ }
+ if (rc != null) {
+ target.addAttribute(VTwinColSelect.ATTRIBUTE_RIGHT_CAPTION, rc);
+ }
+
super.paintContent(target);
}
+ /**
+ * Sets the text shown above the right column.
+ *
+ * @param caption
+ * The text to show
+ */
+ public void setRightColumnCaption(String rightColumnCaption) {
+ this.rightColumnCaption = rightColumnCaption;
+ requestRepaint();
+ }
+
+ /**
+ * Returns the text shown above the right column.
+ *
+ * @return The text shown or null if not set.
+ */
+ public String getRightColumnCaption() {
+ return rightColumnCaption;
+ }
+
+ /**
+ * Sets the text shown above the left column.
+ *
+ * @param caption
+ * The text to show
+ */
+ public void setLeftColumnCaption(String leftColumnCaption) {
+ this.leftColumnCaption = leftColumnCaption;
+ requestRepaint();
+ }
+
+ /**
+ * Returns the text shown above the left column.
+ *
+ * @return The text shown or null if not set.
+ */
+ public String getLeftColumnCaption() {
+ return leftColumnCaption;
+ }
+
}