From 6edd5dd7662bb62bfc48b1d36663f37bf4c11797 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Wed, 25 Nov 2009 14:04:09 +0000 Subject: [PATCH] Variable enhancements * typing map for changevariable to * added variabletypes Object[] and Map where Objects can be Strings,Integers, Longs, Floats, Doubles, Booleans and Paintables (reference on client side translates to corresponding server side component by terminal) * Note, multilevel datastructures still not supported (Array or Map inside another), needs #3765 fixes #3756, #3757 svn changeset:10023/svn branch:6.2 --- src/com/vaadin/terminal/VariableOwner.java | 2 +- .../gwt/client/ApplicationConnection.java | 150 +++++++++---- .../terminal/gwt/client/ui/VListSelect.java | 6 +- .../terminal/gwt/client/ui/VNativeSelect.java | 6 +- .../terminal/gwt/client/ui/VOptionGroup.java | 4 +- .../gwt/client/ui/VOptionGroupBase.java | 8 +- .../terminal/gwt/client/ui/VScrollTable.java | 13 +- .../terminal/gwt/client/ui/VTablePaging.java | 23 +- .../terminal/gwt/client/ui/VTextField.java | 6 + .../vaadin/terminal/gwt/client/ui/VTree.java | 16 +- .../gwt/client/ui/VTwinColSelect.java | 14 +- .../server/AbstractCommunicationManager.java | 206 +++++++++++------- src/com/vaadin/ui/AbstractComponent.java | 2 +- src/com/vaadin/ui/AbstractField.java | 14 +- src/com/vaadin/ui/AbstractSelect.java | 2 +- 15 files changed, 304 insertions(+), 168 deletions(-) diff --git a/src/com/vaadin/terminal/VariableOwner.java b/src/com/vaadin/terminal/VariableOwner.java index 5f6fc03877..1507726b7d 100644 --- a/src/com/vaadin/terminal/VariableOwner.java +++ b/src/com/vaadin/terminal/VariableOwner.java @@ -33,7 +33,7 @@ public interface VariableOwner extends Serializable { * @param variables * the Mapping from variable names to new variable values. */ - public void changeVariables(Object source, Map variables); + public void changeVariables(Object source, Map variables); /** *

diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index d461d2c6ca..02c05358e2 100755 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -9,6 +9,7 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Map; import java.util.Set; import com.google.gwt.core.client.GWT; @@ -216,7 +217,7 @@ public class ApplicationConnection { *

  • vaadin.postRequestHooks is a map of functions which gets * called after each XHR made by vaadin application. Note, that it is * attaching js functions responsibility to create the variable like this: - * + * *
          * if(!vaadin.postRequestHooks) {vaadin.postRequestHooks = new Object();}
          * postRequestHooks.myHook = function(appId) {
    @@ -227,7 +228,7 @@ public class ApplicationConnection {
          * 
    First parameter passed to these functions is the identifier * of Vaadin application that made the request. * - * + * * TODO make this multi-app aware */ private native void initializeClientHooks() @@ -258,7 +259,7 @@ public class ApplicationConnection { /** * Runs possibly registered client side post request hooks. This is expected * to be run after each uidl request made by Vaadin application. - * + * * @param appId */ private static native void runPostRequestHooks(String appId) @@ -281,7 +282,7 @@ public class ApplicationConnection { /** * Checks if client side is in debug mode. Practically this is invoked by * adding ?debug parameter to URI. - * + * * @return true if client side is currently been debugged */ public native static boolean isDebugMode() @@ -356,7 +357,8 @@ public class ApplicationConnection { } } if (windowName != null && windowName.length() > 0) { - uri += (repaintAll || configuration.usePortletURLs() ? "&" : "?") + "windowName=" + windowName; + uri += (repaintAll || configuration.usePortletURLs() ? "&" : "?") + + "windowName=" + windowName; } if (!forceSync) { @@ -462,7 +464,7 @@ public class ApplicationConnection { /** * Shows the communication error notification. The 'details' only go to the * console for now. - * + * * @param details * Optional details for debugging. */ @@ -544,7 +546,7 @@ public class ApplicationConnection { /** * This method is called after applying uidl change set to application. - * + * * It will clean current and queued variable change sets. And send next * change set if it exists. */ @@ -564,7 +566,7 @@ public class ApplicationConnection { /** * Cleans given queue of variable changes of such changes that came from * components that do not exist anymore. - * + * * @param variableBurst */ private void cleanVariableBurst(ArrayList variableBurst) { @@ -921,7 +923,7 @@ public class ApplicationConnection { /** * Returns Paintable element by its id - * + * * @param id * Paintable ID */ @@ -955,12 +957,12 @@ public class ApplicationConnection { /** * This method sends currently queued variable changes to server. It is * called when immediate variable update must happen. - * + * * To ensure correct order for variable changes (due servers multithreading * or network), we always wait for active request to be handler before * sending a new one. If there is an active request, we will put varible * "burst" to queue that will be purged after current request is handled. - * + * */ @SuppressWarnings("unchecked") public void sendPendingVariableChanges() { @@ -982,11 +984,11 @@ public class ApplicationConnection { /** * Build the variable burst and send it to server. - * + * * When sync is forced, we also force sending of all pending variable-bursts * at the same time. This is ok as we can assume that DOM will never be * updated after this. - * + * * @param pendingVariables * Vector of variable changes to send * @param forceSync @@ -1060,6 +1062,64 @@ public class ApplicationConnection { : "false", immediate, 'b'); } + public void updateVariable(String paintableId, String variableName, + Map map, boolean immediate) { + final StringBuffer buf = new StringBuffer(); + Iterator iterator = map.keySet().iterator(); + while (iterator.hasNext()) { + String key = iterator.next(); + Object value = map.get(key); + char transportType = getTransportType(value); + buf.append(transportType); + buf.append(key); + buf.append(VAR_ARRAYITEM_SEPARATOR); + if (transportType == 'p') { + buf.append(getPid((Paintable) value)); + } else { + buf.append(value); + } + + if (iterator.hasNext()) { + buf.append(VAR_ARRAYITEM_SEPARATOR); + } + } + + addVariableToQueue(paintableId, variableName, buf.toString(), + immediate, 'm'); + } + + private char getTransportType(Object value) { + if (value instanceof String) { + return 's'; + } else if (value instanceof Paintable) { + return 'p'; + } else if (value instanceof Boolean) { + return 'b'; + } else if (value instanceof Integer) { + return 'i'; + } else if (value instanceof Float) { + return 'f'; + } else if (value instanceof Double) { + return 'd'; + } else if (value instanceof Long) { + return 'l'; + } + return 'u'; + } + + public void updateVariable(String paintableId, String variableName, + String[] values, boolean immediate) { + final StringBuffer buf = new StringBuffer(); + for (int i = 0; i < values.length; i++) { + if (i > 0) { + buf.append(VAR_ARRAYITEM_SEPARATOR); + } + buf.append(values[i]); + } + addVariableToQueue(paintableId, variableName, buf.toString(), + immediate, 'c'); + } + public void updateVariable(String paintableId, String variableName, Object[] values, boolean immediate) { final StringBuffer buf = new StringBuffer(); @@ -1067,7 +1127,15 @@ public class ApplicationConnection { if (i > 0) { buf.append(VAR_ARRAYITEM_SEPARATOR); } - buf.append(values[i].toString()); + Object value = values[i]; + char transportType = getTransportType(value); + // first char tells the type in array + buf.append(transportType); + if (transportType == 'p') { + buf.append(getPid((Paintable) value)); + } else { + buf.append(value); + } } addVariableToQueue(paintableId, variableName, buf.toString(), immediate, 'a'); @@ -1075,9 +1143,9 @@ public class ApplicationConnection { /** * Update generic component features. - * + * *

    Selecting correct implementation

    - * + * *

    * The implementation of a component depends on many properties, including * styles, component features, etc. Sometimes the user changes those @@ -1085,21 +1153,21 @@ public class ApplicationConnection { * the beginning of your updateFromUIDL -method automatically replaces your * component with more appropriate if the requested implementation changes. *

    - * + * *

    Caption, icon, error messages and description

    - * + * *

    * Component can delegate management of caption, icon, error messages and * description to parent layout. This is optional an should be decided by * component author *

    - * + * *

    Component visibility and disabling

    - * + * * This method will manage component visibility automatically and if * component is an instanceof FocusWidget, also handle component disabling * when needed. - * + * * @param component * Widget to be updated, expected to implement an instance of * Paintable @@ -1108,7 +1176,7 @@ public class ApplicationConnection { * @param manageCaption * True if you want to delegate caption, icon, description and * error message management to parent. - * + * * @return Returns true iff no further painting is needed by caller */ public boolean updateComponent(Widget component, UIDL uidl, @@ -1318,7 +1386,7 @@ public class ApplicationConnection { /** * Traverses recursively child widgets until ContainerResizedListener child * widget is found. They will delegate it further if needed. - * + * * @param container */ private boolean runningLayout = false; @@ -1381,7 +1449,7 @@ public class ApplicationConnection { /** * Converts relative sizes into pixel sizes. - * + * * @param child * @return true if the child has a relative size */ @@ -1528,7 +1596,7 @@ public class ApplicationConnection { /** * Converts relative sizes into pixel sizes. - * + * * @param child * @return true if the child has a relative size */ @@ -1545,12 +1613,12 @@ public class ApplicationConnection { /** * Get either existing or new Paintable for given UIDL. - * + * * If corresponding Paintable has been previously painted, return it. * Otherwise create and register a new Paintable from UIDL. Caller must * update the returned Paintable from UIDL after it has been connected to * parent. - * + * * @param uidl * UIDL to create Paintable from. * @return Either existing or new Paintable corresponding to UIDL. @@ -1570,7 +1638,7 @@ public class ApplicationConnection { /** * Returns a Paintable element by its root element - * + * * @param element * Root element of the paintable */ @@ -1584,7 +1652,7 @@ public class ApplicationConnection { /** * Singleton method to get instance of app's context menu. - * + * * @return VContextMenu object */ public VContextMenu getContextMenu() { @@ -1600,7 +1668,7 @@ public class ApplicationConnection { * Translates custom protocols in UIDL URI's to be recognizable by browser. * All uri's from UIDL should be routed via this method before giving them * to browser due URI's in UIDL may contain custom protocols like theme://. - * + * * @param uidlUri * Vaadin URI from uidl * @return translated URI ready for browser @@ -1628,7 +1696,7 @@ public class ApplicationConnection { /** * Listens for Notification hide event, and redirects. Used for system * messages, such as session expired. - * + * */ private class NotificationRedirect implements VNotification.EventListener { String url; @@ -1648,9 +1716,9 @@ public class ApplicationConnection { /** * Data showed in tooltips are stored centrilized as it may be needed in * varios place: caption, layouts, and in owner components themselves. - * + * * Updating TooltipInfo is done in updateComponent method. - * + * */ public TooltipInfo getTooltipTitleInfo(Paintable titleOwner, Object key) { if (null == titleOwner) { @@ -1670,9 +1738,9 @@ public class ApplicationConnection { * Component may want to delegate Tooltip handling to client. Layouts add * Tooltip (description, errors) to caption, but some components may want * them to appear one other elements too. - * + * * Events wanted by this handler are same as in Tooltip.TOOLTIP_EVENTS - * + * * @param event * @param owner */ @@ -1685,9 +1753,9 @@ public class ApplicationConnection { * Component may want to delegate Tooltip handling to client. Layouts add * Tooltip (description, errors) to caption, but some components may want * them to appear one other elements too. - * + * * Events wanted by this handler are same as in Tooltip.TOOLTIP_EVENTS - * + * * @param event * @param owner * @param key @@ -1701,7 +1769,7 @@ public class ApplicationConnection { /** * Adds PNG-fix conditionally (only for IE6) to the specified IMG -element. - * + * * @param el * the IMG element to fix */ @@ -1751,7 +1819,7 @@ public class ApplicationConnection { * Reset the name of the current browser-window. This should reflect the * window-name used in the server, but might be different from the * window-object target-name on client. - * + * * @param stringAttribute * New name for the window. */ @@ -1781,14 +1849,14 @@ public class ApplicationConnection { *

    * This method can also be used to deregister tooltips by using null as * tooltip - * + * * @param paintable * Paintable "owning" this tooltip * @param key * key assosiated with given tooltip. Can be any object. For * example a related dom element. Same key must be given for * {@link #handleTooltipEvent(Event, Paintable, Object)} method. - * + * * @param tooltip * the TooltipInfo object containing details shown in tooltip, * null if deregistering tooltip diff --git a/src/com/vaadin/terminal/gwt/client/ui/VListSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VListSelect.java index e33231c81b..480685345f 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VListSelect.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VListSelect.java @@ -60,14 +60,14 @@ public class VListSelect extends VOptionGroupBase { } @Override - protected Object[] getSelectedItems() { - final ArrayList selectedItemKeys = new ArrayList(); + protected String[] getSelectedItems() { + final ArrayList selectedItemKeys = new ArrayList(); for (int i = 0; i < select.getItemCount(); i++) { if (select.isItemSelected(i)) { selectedItemKeys.add(select.getValue(i)); } } - return selectedItemKeys.toArray(); + return selectedItemKeys.toArray(new String[selectedItemKeys.size()]); } @Override diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java index 50c7c337ba..8c00e9c1a7 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java @@ -61,14 +61,14 @@ public class VNativeSelect extends VOptionGroupBase implements Field { } @Override - protected Object[] getSelectedItems() { - final ArrayList selectedItemKeys = new ArrayList(); + protected String[] getSelectedItems() { + final ArrayList selectedItemKeys = new ArrayList(); for (int i = 0; i < select.getItemCount(); i++) { if (select.isItemSelected(i)) { selectedItemKeys.add(select.getValue(i)); } } - return selectedItemKeys.toArray(); + return selectedItemKeys.toArray(new String[selectedItemKeys.size()]); } @Override diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java index e54cf04a6c..a8ce1d124e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java @@ -58,8 +58,8 @@ public class VOptionGroup extends VOptionGroupBase { } @Override - protected Object[] getSelectedItems() { - return selectedKeys.toArray(); + protected String[] getSelectedItems() { + return selectedKeys.toArray(new String[selectedKeys.size()]); } @Override diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java index a2c558094c..115c415289 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java @@ -31,7 +31,7 @@ abstract class VOptionGroupBase extends Composite implements Paintable, Field, protected String id; - protected Set selectedKeys; + protected Set selectedKeys; private boolean immediate; @@ -215,10 +215,10 @@ abstract class VOptionGroupBase extends Composite implements Paintable, Field, protected abstract void buildOptions(UIDL uidl); - protected abstract Object[] getSelectedItems(); + protected abstract String[] getSelectedItems(); - protected Object getSelectedItem() { - final Object[] sel = getSelectedItems(); + protected String getSelectedItem() { + final String[] sel = getSelectedItems(); if (sel.length > 0) { return sel[0]; } else { diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java index 575d35e5f0..e735dc67d9 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java @@ -1658,7 +1658,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler { // update variable to server client.updateVariable(paintableId, "collapsedcolumns", - collapsedColumns.toArray(), false); + collapsedColumns.toArray(new String[collapsedColumns + .size()]), false); // let rowRequestHandler determine proper rows rowRequestHandler.refreshContent(); } @@ -2449,8 +2450,14 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler { // might // require changes to "clickEvent" immediateness // also. - client.updateVariable(paintableId, "selected", - selectedRowKeys.toArray(), immediate); + client + .updateVariable( + paintableId, + "selected", + selectedRowKeys + .toArray(new String[selectedRowKeys + .size()]), + immediate); } break; case Event.ONCONTEXTMENU: diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java b/src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java index 6995513524..638f4b9be9 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java @@ -51,7 +51,7 @@ public class VTablePaging extends Composite implements Table, Paintable, private int selectMode = Table.SELECT_MODE_NONE; - private final ArrayList selectedRowKeys = new ArrayList(); + private final ArrayList selectedRowKeys = new ArrayList(); private int totalRows; @@ -108,10 +108,11 @@ public class VTablePaging extends Composite implements Table, Paintable, } if (uidl.hasAttribute("selected")) { - final Set selectedKeys = uidl + final Set selectedKeys = uidl .getStringArrayVariableAsSet("selected"); selectedRowKeys.clear(); - for (final Iterator it = selectedKeys.iterator(); it.hasNext();) { + for (final Iterator it = selectedKeys.iterator(); it + .hasNext();) { selectedRowKeys.add(it.next()); } } @@ -169,10 +170,10 @@ public class VTablePaging extends Composite implements Table, Paintable, /** * Updates row data from uidl. UpdateFromUIDL delegates updating tBody to * this method. - * + * * Updates may be to different part of tBody, depending on update type. It * can be initial row data, scroll up, scroll down... - * + * * @param uidl * which contains row data */ @@ -299,7 +300,7 @@ public class VTablePaging extends Composite implements Table, Paintable, /** * Abstraction of table cell content. In needs to know on which row it is in * case of context click. - * + * * @author mattitahvonen */ public class BodyCell extends SimplePanel { @@ -355,7 +356,7 @@ public class VTablePaging extends Composite implements Table, Paintable, /** * This method is used to set row status. Does not change value on * server. - * + * * @param selected */ public void setSelected(boolean sel) { @@ -379,7 +380,7 @@ public class VTablePaging extends Composite implements Table, Paintable, /** * Toggles rows select state. Also updates state to server according to * tables immediate flag. - * + * */ public void toggleSelected() { if (selected) { @@ -390,13 +391,13 @@ public class VTablePaging extends Composite implements Table, Paintable, } setSelected(true); } - client.updateVariable(id, "selected", selectedRowKeys.toArray(), - immediate); + client.updateVariable(id, "selected", selectedRowKeys + .toArray(new String[selectedRowKeys.size()]), immediate); } /** * Shows context menu for this row. - * + * * @param event * Event which triggered context menu. Correct place for * context menu can be determined with it. diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java b/src/com/vaadin/terminal/gwt/client/ui/VTextField.java index 845a50e793..8c02fc33cf 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTextField.java @@ -56,6 +56,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field, private static final String ATTR_INPUTPROMPT = "prompt"; private String inputPrompt = null; private boolean prompting = false; + private boolean listenFocus; public VTextField() { this(DOM.createInputText()); @@ -98,6 +99,8 @@ public class VTextField extends TextBoxBase implements Paintable, Field, setReadOnly(false); } + listenFocus = uidl.getBooleanAttribute("listenFocus"); + inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT); setMaxLength(uidl.hasAttribute("maxLength") ? uidl @@ -195,6 +198,9 @@ public class VTextField extends TextBoxBase implements Paintable, Field, } } focusedTextField = this; + if (listenFocus) { + client.updateVariable(id, "focus", true, true); + } } public void onBlur(BlurEvent event) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTree.java b/src/com/vaadin/terminal/gwt/client/ui/VTree.java index 87d27caa55..7769047c80 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTree.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTree.java @@ -169,8 +169,20 @@ public class VTree extends FlowPanel implements Paintable { selectedIds.remove(treeNode.key); treeNode.setSelected(false); } - client.updateVariable(paintableId, "selected", selectedIds.toArray(), - immediate); + + Object[] foo = new Object[] { new Integer(33), new Float(3.2f), + new Long(222), this, "bar", true, new Double(3.33332) }; + client.updateVariable(paintableId, "foo", foo, false); + + HashMap bar = new HashMap(); + bar.put("paintable", this); + bar.put("String", "bar"); + bar.put("Integer", 33); + + client.updateVariable(paintableId, "bar", bar, false); + + client.updateVariable(paintableId, "selected", selectedIds + .toArray(new String[selectedIds.size()]), immediate); } public boolean isSelected(TreeNode treeNode) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java index 1694992074..880144a11b 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java @@ -110,12 +110,12 @@ public class VTwinColSelect extends VOptionGroupBase { } @Override - protected Object[] getSelectedItems() { - final ArrayList selectedItemKeys = new ArrayList(); + protected String[] getSelectedItems() { + final ArrayList selectedItemKeys = new ArrayList(); for (int i = 0; i < selections.getItemCount(); i++) { selectedItemKeys.add(selections.getValue(i)); } - return selectedItemKeys.toArray(); + return selectedItemKeys.toArray(new String[selectedItemKeys.size()]); } private boolean[] getItemsToAdd() { @@ -162,8 +162,8 @@ public class VTwinColSelect extends VOptionGroupBase { options.removeItem(optionIndex); } } - client.updateVariable(id, "selected", selectedKeys.toArray(), - isImmediate()); + client.updateVariable(id, "selected", selectedKeys + .toArray(new String[selectedKeys.size()]), isImmediate()); } else if (event.getSource() == remove) { final boolean[] sel = getItemsToRemove(); @@ -181,8 +181,8 @@ public class VTwinColSelect extends VOptionGroupBase { selections.removeItem(selectionIndex); } } - client.updateVariable(id, "selected", selectedKeys.toArray(), - isImmediate()); + client.updateVariable(id, "selected", selectedKeys + .toArray(new String[selectedKeys.size()]), isImmediate()); } else if (event.getSource() == options) { // unselect all in other list, to avoid mistakes (i.e wrong button) final int c = selections.getItemCount(); diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index 7e9c04bc26..34d37fca06 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -70,7 +70,7 @@ import com.vaadin.ui.Upload.UploadException; * communication system between the client code (compiled with GWT into * JavaScript) and the server side components. Its client side counterpart is * {@link ApplicationConnection}. - * + * * A server side component sends its state to the client in a paint request (see * {@link Paintable} and {@link PaintTarget} on the server side). The client * widget receives these paint requests as calls to @@ -78,7 +78,7 @@ import com.vaadin.ui.Upload.UploadException; * component communicates back to the server by sending a list of variable * changes (see {@link ApplicationConnection#updateVariable()} and * {@link VariableOwner#changeVariables(Object, Map)}). - * + * * TODO Document better! */ @SuppressWarnings("serial") @@ -87,13 +87,13 @@ public abstract class AbstractCommunicationManager implements /** * Generic interface of a (HTTP or Portlet) request to the application. - * + * * This is a wrapper interface that allows * {@link AbstractCommunicationManager} to use a unified API. - * + * * @see javax.servlet.ServletRequest * @see javax.portlet.PortletRequest - * + * * @author peholmst */ protected interface Request { @@ -101,9 +101,9 @@ public abstract class AbstractCommunicationManager implements /** * Gets a {@link Session} wrapper implementation representing the * session for which this request was sent. - * + * * Multiple Vaadin applications can be associated with a single session. - * + * * @return Session */ public Session getSession(); @@ -111,17 +111,17 @@ public abstract class AbstractCommunicationManager implements /** * Are the applications in this session running in a portlet or directly * as servlets. - * + * * @return true if in a portlet */ public boolean isRunningInPortlet(); /** * Get the named HTTP or portlet request parameter. - * + * * @see javax.servlet.ServletRequest#getParameter(String) * @see javax.portlet.PortletRequest#getParameter(String) - * + * * @param name * @return */ @@ -130,7 +130,7 @@ public abstract class AbstractCommunicationManager implements /** * Returns the length of the request content that can be read from the * input stream returned by {@link #getInputStream()}. - * + * * @return content length in bytes */ public int getContentLength(); @@ -139,7 +139,7 @@ public abstract class AbstractCommunicationManager implements * Returns an input stream from which the request content can be read. * The request content length can be obtained with * {@link #getContentLength()} without reading the full stream contents. - * + * * @return * @throws IOException */ @@ -148,7 +148,7 @@ public abstract class AbstractCommunicationManager implements /** * Returns the request identifier that identifies the target Vaadin * window for the request. - * + * * @return String identifier for the request target window */ public String getRequestID(); @@ -168,7 +168,7 @@ public abstract class AbstractCommunicationManager implements /** * Gets the underlying request object. The request is typically either a * {@link ServletRequest} or a {@link PortletRequest}. - * + * * @return wrapped request object */ public Object getWrappedRequest(); @@ -177,20 +177,20 @@ public abstract class AbstractCommunicationManager implements /** * Generic interface of a (HTTP or Portlet) response from the application. - * + * * This is a wrapper interface that allows * {@link AbstractCommunicationManager} to use a unified API. - * + * * @see javax.servlet.ServletResponse * @see javax.portlet.PortletResponse - * + * * @author peholmst */ protected interface Response { /** * Gets the output stream to which the response can be written. - * + * * @return * @throws IOException */ @@ -199,7 +199,7 @@ public abstract class AbstractCommunicationManager implements /** * Sets the MIME content type for the response to be communicated to the * browser. - * + * * @param type */ public void setContentType(String type); @@ -207,7 +207,7 @@ public abstract class AbstractCommunicationManager implements /** * Gets the wrapped response object, usually a class implementing either * {@link ServletResponse} or {@link PortletResponse}. - * + * * @return wrapped request object */ public Object getWrappedResponse(); @@ -216,14 +216,14 @@ public abstract class AbstractCommunicationManager implements /** * Generic wrapper interface for a (HTTP or Portlet) session. - * + * * Several applications can be associated with a single session. - * + * * TODO Document me! - * + * * @see javax.servlet.http.HttpSession * @see javax.portlet.PortletSession - * + * * @author peholmst */ protected interface Session { @@ -242,7 +242,7 @@ public abstract class AbstractCommunicationManager implements /** * TODO Document me! - * + * * @author peholmst */ protected interface Callback { @@ -270,6 +270,17 @@ public abstract class AbstractCommunicationManager implements private static final int VAR_TYPE = 3; private static final int VAR_VALUE = 0; + private static final char VTYPE_PAINTABLE = 'p'; + private static final char VTYPE_BOOLEAN = 'b'; + private static final char VTYPE_DOUBLE = 'd'; + private static final char VTYPE_FLOAT = 'f'; + private static final char VTYPE_LONG = 'l'; + private static final char VTYPE_INTEGER = 'i'; + private static final char VTYPE_STRING = 's'; + private static final char VTYPE_ARRAY = 'a'; + private static final char VTYPE_STRINGARRAY = 'c'; + private static final char VTYPE_MAP = 'm'; + private static final String VAR_RECORD_SEPARATOR = "\u001e"; private static final String VAR_FIELD_SEPARATOR = "\u001f"; @@ -306,7 +317,7 @@ public abstract class AbstractCommunicationManager implements /** * TODO New constructor - document me! - * + * * @param application */ public AbstractCommunicationManager(Application application) { @@ -317,26 +328,27 @@ public abstract class AbstractCommunicationManager implements /** * Create an upload handler that is appropriate to the context in which the * application is being run (servlet or portlet). - * + * * @return new {@link FileUpload} instance */ protected abstract FileUpload createFileUpload(); /** * TODO New method - document me! - * + * * @param upload * @param request * @return * @throws IOException * @throws FileUploadException */ - protected abstract FileItemIterator getUploadItemIterator(FileUpload upload, - Request request) throws IOException, FileUploadException; + protected abstract FileItemIterator getUploadItemIterator( + FileUpload upload, Request request) throws IOException, + FileUploadException; /** * TODO New method - document me! - * + * * @param request * @param response * @throws IOException @@ -431,12 +443,13 @@ public abstract class AbstractCommunicationManager implements /** * TODO document - * + * * @param request * @param response * @throws IOException */ - protected void sendUploadResponse(Request request, Response response) throws IOException { + protected void sendUploadResponse(Request request, Response response) + throws IOException { response.setContentType("text/html"); final OutputStream out = response.getOutputStream(); final PrintWriter outWriter = new PrintWriter(new BufferedWriter( @@ -448,19 +461,19 @@ public abstract class AbstractCommunicationManager implements /** * Internally process a UIDL request from the client. - * + * * This method calls * {@link #handleVariables(Request, Response, Callback, Application, Window)} * to process any changes to variables by the client and then repaints * affected components using {@link #paintAfterVariableChanges()}. - * + * * Also, some cleanup is done when a request arrives for an application that * has already been closed. - * + * * The method handleUidlRequest(...) in subclasses should call this method. - * + * * TODO better documentation - * + * * @param request * @param response * @param callback @@ -476,7 +489,7 @@ public abstract class AbstractCommunicationManager implements final OutputStream out; repaintAll = (request.getParameter(GET_PARAM_REPAINT_ALL) != null); - //|| (request.getSession().isNew()); FIXME What the h*ll is this?? + // || (request.getSession().isNew()); FIXME What the h*ll is this?? out = response.getOutputStream(); boolean analyzeLayouts = false; @@ -554,13 +567,13 @@ public abstract class AbstractCommunicationManager implements } } - //out.flush(); - this line will cause errors when deployed on GateIn. + // out.flush(); - this line will cause errors when deployed on GateIn. out.close(); } /** * TODO document - * + * * @param request * @param response * @param callback @@ -916,11 +929,11 @@ public abstract class AbstractCommunicationManager implements /** * TODO document - * + * * If this method returns false, something was submitted that we did not * expect; this is probably due to the client being out-of-sync and sending * variable changes for non-existing pids - * + * * @return true if successful, false if there was an inconsistency */ private boolean handleVariables(Request request, Response response, @@ -980,20 +993,19 @@ public abstract class AbstractCommunicationManager implements // TODO this should be Map, but the // VariableOwner API does not guarantee the key is a // string - Map m; + Map m; if (nextVariable != null && variable[VAR_PID] .equals(nextVariable[VAR_PID])) { // we have more than one value changes in row for // one variable owner, collect em in HashMap - m = new HashMap(); + m = new HashMap(); m.put(variable[VAR_NAME], convertVariableValue( variable[VAR_TYPE].charAt(0), variable[VAR_VALUE])); } else { // use optimized single value map - m = Collections.singletonMap( - (Object) variable[VAR_NAME], + m = Collections.singletonMap(variable[VAR_NAME], convertVariableValue(variable[VAR_TYPE] .charAt(0), variable[VAR_VALUE])); } @@ -1084,7 +1096,7 @@ public abstract class AbstractCommunicationManager implements /** * Reads the request data from the Request and returns it converted to an * UTF-8 string. - * + * * @param request * @return * @throws IOException @@ -1129,13 +1141,13 @@ public abstract class AbstractCommunicationManager implements /** * Handles an error (exception) that occurred when processing variable * changes from the client or a failure of a file upload. - * + * * For {@link AbstractField} components, * {@link AbstractField#handleError(com.vaadin.ui.AbstractComponent.ComponentErrorEvent)} * is called. In all other cases (or if the field does not handle the * error), {@link ErrorListener#terminalError(ErrorEvent)} for the * application error handler is called. - * + * * @param application * @param owner * component that the error concerns @@ -1174,28 +1186,34 @@ public abstract class AbstractCommunicationManager implements private Object convertVariableValue(char variableType, String strValue) { Object val = null; switch (variableType) { - case 'a': + case VTYPE_ARRAY: + val = convertArray(strValue); + break; + case VTYPE_MAP: + val = convertMap(strValue); + break; + case VTYPE_STRINGARRAY: val = strValue.split(VAR_ARRAYITEM_SEPARATOR); break; - case 's': + case VTYPE_STRING: val = strValue; break; - case 'i': + case VTYPE_INTEGER: val = Integer.valueOf(strValue); break; - case 'l': + case VTYPE_LONG: val = Long.valueOf(strValue); break; - case 'f': + case VTYPE_FLOAT: val = Float.valueOf(strValue); break; - case 'd': + case VTYPE_DOUBLE: val = Double.valueOf(strValue); break; - case 'b': + case VTYPE_BOOLEAN: val = Boolean.valueOf(strValue); break; - case 'p': + case VTYPE_PAINTABLE: val = idPaintableMap.get(strValue); break; } @@ -1203,11 +1221,35 @@ public abstract class AbstractCommunicationManager implements return val; } + private Object convertMap(String strValue) { + String[] parts = strValue.split(VAR_ARRAYITEM_SEPARATOR); + HashMap map = new HashMap(); + for (int i = 0; i < parts.length; i += 2) { + String key = parts[i]; + char variabletype = key.charAt(0); + Object value = convertVariableValue(variabletype, parts[i + 1]); + map.put(key.substring(1), value); + } + return map; + } + + private Object convertArray(String strValue) { + String[] val = strValue.split(VAR_ARRAYITEM_SEPARATOR); + Object[] values = new Object[val.length]; + for (int i = 0; i < values.length; i++) { + String string = val[i]; + // first char of string is typ + char variableType = string.charAt(0); + values[i] = convertVariableValue(variableType, string.substring(1)); + } + return values; + } + /** - * Prints the queued (pending) locale definitions to a {@link PrintWriter} in - * a (UIDL) format that can be sent to the client and used there in formatting - * dates, times etc. - * + * Prints the queued (pending) locale definitions to a {@link PrintWriter} + * in a (UIDL) format that can be sent to the client and used there in + * formatting dates, times etc. + * * @param outWriter */ private void printLocaleDeclarations(PrintWriter outWriter) { @@ -1316,7 +1358,7 @@ public abstract class AbstractCommunicationManager implements final String timeformat = df.substring(timeStart, df.length()); /* * Doesn't return second or milliseconds. - * + * * We use timeformat to determine 12/24-hour clock */ final boolean twelve_hour_clock = timeformat.indexOf("a") > -1; @@ -1342,7 +1384,7 @@ public abstract class AbstractCommunicationManager implements /** * TODO New method - document me! - * + * * @param request * @param callback * @param application @@ -1429,11 +1471,11 @@ public abstract class AbstractCommunicationManager implements /** * Ends the Application. - * + * * The browser is redirected to the Application logout URL set with * {@link Application#setLogoutURL(String)}, or to the application URL if no * logout URL is given. - * + * * @param request * the request instance. * @param response @@ -1468,7 +1510,7 @@ public abstract class AbstractCommunicationManager implements /** * Gets the Paintable Id. If Paintable has debug id set it will be used * prefixed with "PID_S". Otherwise a sequenced ID is created. - * + * * @param paintable * @return the paintable Id. */ @@ -1514,7 +1556,7 @@ public abstract class AbstractCommunicationManager implements /** * Returns dirty components which are in given window. Components in an * invisible subtrees are omitted. - * + * * @param w * root window for which dirty components is to be fetched * @return @@ -1549,7 +1591,7 @@ public abstract class AbstractCommunicationManager implements && !component.getParent().isVisible()) { /* * Do not return components in an invisible subtree. - * + * * Components that are invisible in visible subree, must * be rendered (to let client know that they need to be * hidden). @@ -1576,7 +1618,7 @@ public abstract class AbstractCommunicationManager implements /** * Internally mark a {@link Paintable} as painted and start collecting new * repaint requests for it. - * + * * @param paintable */ private void paintablePainted(Paintable paintable) { @@ -1595,7 +1637,7 @@ public abstract class AbstractCommunicationManager implements private final Throwable throwable; /** - * + * * @param owner * @param throwable */ @@ -1623,11 +1665,11 @@ public abstract class AbstractCommunicationManager implements * Queues a locale to be sent to the client (browser) for date and time * entry etc. All locale specific information is derived from server-side * {@link Locale} instances and sent to the client when needed, eliminating - * the need to use the {@link Locale} class and all the framework behind - * it on the client. - * + * the need to use the {@link Locale} class and all the framework behind it + * on the client. + * * @see Locale#toString() - * + * * @param value */ public void requireLocale(String value) { @@ -1644,9 +1686,9 @@ public abstract class AbstractCommunicationManager implements /** * Constructs a {@link Locale} instance to be sent to the client based on a * short locale description string. - * + * * @see #requireLocale(String) - * + * * @param value * @return */ @@ -1687,7 +1729,7 @@ public abstract class AbstractCommunicationManager implements /** * Helper method to test if a component contains another - * + * * @param parent * @param child */ @@ -1714,12 +1756,12 @@ public abstract class AbstractCommunicationManager implements /** * Calls the Window URI handler for a request and returns the * {@link DownloadStream} returned by the handler. - * + * * If the window is the main window of an application, the (deprecated) * {@link Application#handleURI(java.net.URL, String)} is called first to * handle {@link ApplicationResource}s, and the window handler is only * called if it returns null. - * + * * @param window * the target window of the request * @param request @@ -1799,7 +1841,7 @@ public abstract class AbstractCommunicationManager implements /** * Helper class for terminal to keep track of data that client is expected * to know. - * + * * TODO make customlayout templates (from theme) to be cached here. */ class OpenWindowCache implements Serializable { @@ -1807,7 +1849,7 @@ public abstract class AbstractCommunicationManager implements private Set res = new HashSet(); /** - * + * * @param paintable * @return true if the given class was added to cache */ diff --git a/src/com/vaadin/ui/AbstractComponent.java b/src/com/vaadin/ui/AbstractComponent.java index 2e6a0d6e19..dbf988377f 100644 --- a/src/com/vaadin/ui/AbstractComponent.java +++ b/src/com/vaadin/ui/AbstractComponent.java @@ -820,7 +820,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource * comment here, we use the default documentation from implemented * interface. */ - public void changeVariables(Object source, Map variables) { + public void changeVariables(Object source, Map variables) { } /* General event framework */ diff --git a/src/com/vaadin/ui/AbstractField.java b/src/com/vaadin/ui/AbstractField.java index 9d1420a78d..d665650dd1 100644 --- a/src/com/vaadin/ui/AbstractField.java +++ b/src/com/vaadin/ui/AbstractField.java @@ -34,15 +34,15 @@ import com.vaadin.terminal.PaintTarget; *

    * *

    - * AbstractField also provides the {@link com.vaadin.data.Buffered} - * interface for buffering the data source value. By default the Field is in - * write through-mode and {@link #setWriteThrough(boolean)}should be called to - * enable buffering. + * AbstractField also provides the {@link com.vaadin.data.Buffered} interface + * for buffering the data source value. By default the Field is in write + * through-mode and {@link #setWriteThrough(boolean)}should be called to enable + * buffering. *

    * *

    - * The class also supports {@link com.vaadin.data.Validator validators} - * to make sure the value contained in the field is valid. + * The class also supports {@link com.vaadin.data.Validator validators} to make + * sure the value contained in the field is valid. *

    * * @author IT Mill Ltd. @@ -940,7 +940,7 @@ public abstract class AbstractField extends AbstractComponent implements Field, } @Override - public void changeVariables(Object source, Map variables) { + public void changeVariables(Object source, Map variables) { super.changeVariables(source, variables); } diff --git a/src/com/vaadin/ui/AbstractSelect.java b/src/com/vaadin/ui/AbstractSelect.java index 767fc21bd2..66cdaf8a65 100644 --- a/src/com/vaadin/ui/AbstractSelect.java +++ b/src/com/vaadin/ui/AbstractSelect.java @@ -358,7 +358,7 @@ public abstract class AbstractSelect extends AbstractField implements * java.util.Map) */ @Override - public void changeVariables(Object source, Map variables) { + public void changeVariables(Object source, Map variables) { super.changeVariables(source, variables); // New option entered (and it is allowed) -- 2.39.5