summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
authorPetter Holmström <petter.holmstrom@itmill.com>2009-11-17 11:15:08 +0000
committerPetter Holmström <petter.holmstrom@itmill.com>2009-11-17 11:15:08 +0000
commit375baea875ff03d5d91229fa7446f9ebcb089082 (patch)
tree977d28d75adb96f4a5b27f935c5f62ba6259843e /src/com
parent4023f7c379387e41a0a3486e0731884038b7bb3f (diff)
parent2772a7d63efa97318944413b0db8fe06c31cfaaa (diff)
downloadvaadin-framework-375baea875ff03d5d91229fa7446f9ebcb089082.tar.gz
vaadin-framework-375baea875ff03d5d91229fa7446f9ebcb089082.zip
Merge with 6.2
svn changeset:9833/svn branch:portlet_2.0
Diffstat (limited to 'src/com')
-rw-r--r--src/com/vaadin/data/util/BeanItemContainer.java2
-rw-r--r--src/com/vaadin/data/util/IndexedContainer.java4
-rw-r--r--src/com/vaadin/data/util/MethodProperty.java16
-rw-r--r--src/com/vaadin/data/validator/CompositeValidator.java4
-rw-r--r--src/com/vaadin/portal/gwt/PortalDefaultWidgetSet.gwt.xml2
-rw-r--r--src/com/vaadin/service/ApplicationContext.java40
-rw-r--r--src/com/vaadin/terminal/SystemError.java15
-rw-r--r--src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml14
-rwxr-xr-xsrc/com/vaadin/terminal/gwt/client/ApplicationConnection.java8
-rw-r--r--src/com/vaadin/terminal/gwt/client/VCaption.java8
-rw-r--r--src/com/vaadin/terminal/gwt/client/VErrorMessage.java17
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/Icon.java3
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java6
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java22
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java445
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VOverlay.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java37
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VPopupView.java21
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java14
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java58
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTextField.java28
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java676
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VUpload.java19
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VView.java18
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VWindow.java198
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java113
-rw-r--r--src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java33
-rw-r--r--src/com/vaadin/terminal/gwt/server/WebApplicationContext.java63
-rw-r--r--src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java27
-rw-r--r--src/com/vaadin/terminal/gwt/widgetsetutils/WidgetSetBuilder.java72
-rw-r--r--src/com/vaadin/ui/Button.java8
-rw-r--r--src/com/vaadin/ui/DateField.java42
-rw-r--r--src/com/vaadin/ui/LoginForm.java4
-rw-r--r--src/com/vaadin/ui/MenuBar.java162
-rw-r--r--src/com/vaadin/ui/TabSheet.java108
-rw-r--r--src/com/vaadin/ui/Upload.java2
-rw-r--r--src/com/vaadin/ui/Window.java50
37 files changed, 1562 insertions, 798 deletions
diff --git a/src/com/vaadin/data/util/BeanItemContainer.java b/src/com/vaadin/data/util/BeanItemContainer.java
index 03616821bf..aaa7d9cd56 100644
--- a/src/com/vaadin/data/util/BeanItemContainer.java
+++ b/src/com/vaadin/data/util/BeanItemContainer.java
@@ -414,7 +414,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
if (va == null) {
return (vb == null) ? 0 : -1;
} else if (vb == null) {
- return (va == null) ? 0 : 1;
+ return 1;
}
return va.compareTo(vb);
diff --git a/src/com/vaadin/data/util/IndexedContainer.java b/src/com/vaadin/data/util/IndexedContainer.java
index 296a1b0072..15c36953a1 100644
--- a/src/com/vaadin/data/util/IndexedContainer.java
+++ b/src/com/vaadin/data/util/IndexedContainer.java
@@ -681,7 +681,7 @@ public class IndexedContainer implements Container.Indexed,
private Serializable generateId() {
Serializable id;
do {
- id = new Integer(nextGeneratedItemId++);
+ id = Integer.valueOf(nextGeneratedItemId++);
} while (items.containsKey(id));
return id;
@@ -1387,7 +1387,7 @@ public class IndexedContainer implements Container.Indexed,
for (int i = 0; i < propertyId.length; i++) {
if (sortable.contains(propertyId[i])) {
ids.add(propertyId[i]);
- orders.add(new Boolean(i < ascending.length ? ascending[i]
+ orders.add(Boolean.valueOf(i < ascending.length ? ascending[i]
: true));
}
}
diff --git a/src/com/vaadin/data/util/MethodProperty.java b/src/com/vaadin/data/util/MethodProperty.java
index 5b15b66cd5..d0a6a9cbd7 100644
--- a/src/com/vaadin/data/util/MethodProperty.java
+++ b/src/com/vaadin/data/util/MethodProperty.java
@@ -473,21 +473,21 @@ public class MethodProperty implements Property, Property.ValueChangeNotifier,
// Gets the return type from get method
if (type.isPrimitive()) {
if (type.equals(Boolean.TYPE)) {
- type = Boolean.class;
+ this.type = Boolean.class;
} else if (type.equals(Integer.TYPE)) {
- type = Integer.class;
+ this.type = Integer.class;
} else if (type.equals(Float.TYPE)) {
- type = Float.class;
+ this.type = Float.class;
} else if (type.equals(Double.TYPE)) {
- type = Double.class;
+ this.type = Double.class;
} else if (type.equals(Byte.TYPE)) {
- type = Byte.class;
+ this.type = Byte.class;
} else if (type.equals(Character.TYPE)) {
- type = Character.class;
+ this.type = Character.class;
} else if (type.equals(Short.TYPE)) {
- type = Short.class;
+ this.type = Short.class;
} else if (type.equals(Long.TYPE)) {
- type = Long.class;
+ this.type = Long.class;
}
}
diff --git a/src/com/vaadin/data/validator/CompositeValidator.java b/src/com/vaadin/data/validator/CompositeValidator.java
index 99eb15b422..8fa01affba 100644
--- a/src/com/vaadin/data/validator/CompositeValidator.java
+++ b/src/com/vaadin/data/validator/CompositeValidator.java
@@ -191,8 +191,8 @@ public class CompositeValidator extends AbstractValidator {
*/
@Override
public String getErrorMessage() {
- if (getErrorMessage() != null) {
- return getErrorMessage();
+ if (super.getErrorMessage() != null) {
+ return super.getErrorMessage();
}
// TODO Return composite error message
diff --git a/src/com/vaadin/portal/gwt/PortalDefaultWidgetSet.gwt.xml b/src/com/vaadin/portal/gwt/PortalDefaultWidgetSet.gwt.xml
index 0963760035..682534e16e 100644
--- a/src/com/vaadin/portal/gwt/PortalDefaultWidgetSet.gwt.xml
+++ b/src/com/vaadin/portal/gwt/PortalDefaultWidgetSet.gwt.xml
@@ -1,4 +1,6 @@
<module>
+ <!-- WS Compiler: manually edited -->
+
<!-- Inherit the SamplerWidgetSet -->
<inherits name="com.vaadin.demo.sampler.gwt.SamplerWidgetSet" />
</module>
diff --git a/src/com/vaadin/service/ApplicationContext.java b/src/com/vaadin/service/ApplicationContext.java
index 96a6f60906..756a8e50c8 100644
--- a/src/com/vaadin/service/ApplicationContext.java
+++ b/src/com/vaadin/service/ApplicationContext.java
@@ -14,7 +14,8 @@ import com.vaadin.terminal.ApplicationResource;
/**
* <code>ApplicationContext</code> provides information about the running
* context of the application. Each context is shared by all applications that
- * are open for one user. In web-environment this corresponds to HttpSession.
+ * are open for one user. In a web-environment this corresponds to a
+ * HttpSession.
*
* @author IT Mill Ltd.
* @version
@@ -26,28 +27,28 @@ public interface ApplicationContext extends Serializable {
/**
* Returns application context base directory.
*
- * Typically an application is deployed in a such way that is has
+ * Typically an application is deployed in a such way that is has an
* application directory. For web applications this directory is the root
- * directory of the web applications. In some cases application might not
- * have application directory (for example web applications running inside
- * of war).
+ * directory of the web applications. In some cases applications might not
+ * have an application directory (for example web applications running
+ * inside a war).
*
- * @return The application base directory
+ * @return The application base directory or null if the application has no
+ * base directory.
*/
public File getBaseDirectory();
/**
- * Gets the applications in this context.
+ * Returns a collection of all the applications in this context.
*
- * Gets all applications in this context. Each application context contains
- * all applications that are open for one user.
+ * Each application context contains all active applications for one user.
*
- * @return Collection containing all applications in this context
+ * @return A collection containing all the applications in this context.
*/
public Collection<Application> getApplications();
/**
- * Adds transaction listener to this context.
+ * Adds a transaction listener to this context.
*
* @param listener
* the listener to be added.
@@ -56,7 +57,7 @@ public interface ApplicationContext extends Serializable {
public void addTransactionListener(TransactionListener listener);
/**
- * Removes transaction listener from this context.
+ * Removes a transaction listener from this context.
*
* @param listener
* the listener to be removed.
@@ -65,9 +66,8 @@ public interface ApplicationContext extends Serializable {
public void removeTransactionListener(TransactionListener listener);
/**
- * Interface for listening the application transaction events.
- * Implementations of this interface can be used to listen all transactions
- * between the client and the application.
+ * Interface for listening to transaction events. Implement this interface
+ * to listen to all transactions between the client and the application.
*
*/
public interface TransactionListener extends Serializable {
@@ -75,6 +75,11 @@ public interface ApplicationContext extends Serializable {
/**
* Invoked at the beginning of every transaction.
*
+ * The transaction is linked to the context, not the application so if
+ * you have multiple applications running in the same context you need
+ * to check that the request is associated with the application you are
+ * interested in. This can be done looking at the application parameter.
+ *
* @param application
* the Application object.
* @param transactionData
@@ -86,6 +91,11 @@ public interface ApplicationContext extends Serializable {
/**
* Invoked at the end of every transaction.
*
+ * The transaction is linked to the context, not the application so if
+ * you have multiple applications running in the same context you need
+ * to check that the request is associated with the application you are
+ * interested in. This can be done looking at the application parameter.
+ *
* @param applcation
* the Application object.
* @param transactionData
diff --git a/src/com/vaadin/terminal/SystemError.java b/src/com/vaadin/terminal/SystemError.java
index 6f29970f6b..8b721c07f5 100644
--- a/src/com/vaadin/terminal/SystemError.java
+++ b/src/com/vaadin/terminal/SystemError.java
@@ -75,20 +75,27 @@ public class SystemError extends RuntimeException implements ErrorMessage {
target.startTag("error");
target.addAttribute("level", "system");
- // Paint the error message
+ StringBuilder sb = new StringBuilder();
final String message = getLocalizedMessage();
if (message != null) {
- target.addSection("h2", message);
+ sb.append("<h2>");
+ sb.append(message);
+ sb.append("</h2>");
}
// Paint the exception
if (cause != null) {
- target.addSection("h3", "Exception");
+ sb.append("<h3>Exception</h3>");
final StringWriter buffer = new StringWriter();
cause.printStackTrace(new PrintWriter(buffer));
- target.addSection("pre", buffer.toString());
+ sb.append("<pre>");
+ sb.append(buffer.toString());
+ sb.append("</pre>");
}
+ target.addXMLSection("div", sb.toString(),
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
+
target.endTag("error");
}
diff --git a/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml b/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml
index 0c139aabc4..d7cf1ca4d0 100644
--- a/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml
+++ b/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml
@@ -1,18 +1,14 @@
<module>
<!--
+
This GWT module defines the Vaadin DefaultWidgetSet. This is
the module you want to extend when creating an extended widget set, or
when creating a specialized widget set with a subset of the
components.
- -->
- <!--
- NOTE that your WidgetSet entry-point (.java) should have the same
- "logical" name (a.k.a SimpleName) as the specification (.gwt.xml).
- -->
- <!--
- E.g: com/example/gwt/MyWidgetSet.gwt.xml should point to the
- entry-point
- com.example.gwt.client[.some.package].MyWidgetSet.java
+
+
+ WS Compiler: manually edited
+
-->
<inherits name="com.google.gwt.user.User" />
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
index 4719b0cbd3..8ea94fcc6b 100755
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
@@ -346,7 +346,6 @@ public class ApplicationConnection {
}
if (!forceSync) {
- boolean success = false;
final RequestBuilder rb = new RequestBuilder(RequestBuilder.POST,
uri);
// TODO enable timeout
@@ -369,11 +368,14 @@ public class ApplicationConnection {
+ String.valueOf((new Date()).getTime()
- requestStartTime.getTime()) + "ms");
- switch (response.getStatusCode()) {
+ int statusCode = response.getStatusCode();
+ switch (statusCode) {
case 0:
showCommunicationError("Invalid status code 0 (server down?)");
return;
- // TODO could add more cases
+ case 404:
+ showCommunicationError("UIDL could not be read from server. Check servlets mappings.");
+ return;
case 503:
// We'll assume msec instead of the usual seconds
int delay = Integer.parseInt(response
diff --git a/src/com/vaadin/terminal/gwt/client/VCaption.java b/src/com/vaadin/terminal/gwt/client/VCaption.java
index de40940ad2..5a6306b79b 100644
--- a/src/com/vaadin/terminal/gwt/client/VCaption.java
+++ b/src/com/vaadin/terminal/gwt/client/VCaption.java
@@ -343,26 +343,26 @@ public class VCaption extends HTML {
int h;
if (icon != null) {
- h = icon.getOffsetHeight();
+ h = Util.getRequiredHeight(icon.getElement());
if (h > height) {
height = h;
}
}
if (captionText != null) {
- h = captionText.getOffsetHeight();
+ h = Util.getRequiredHeight(captionText);
if (h > height) {
height = h;
}
}
if (requiredFieldIndicator != null) {
- h = requiredFieldIndicator.getOffsetHeight();
+ h = Util.getRequiredHeight(requiredFieldIndicator);
if (h > height) {
height = h;
}
}
if (errorIndicatorElement != null) {
- h = errorIndicatorElement.getOffsetHeight();
+ h = Util.getRequiredHeight(errorIndicatorElement);
if (h > height) {
height = h;
}
diff --git a/src/com/vaadin/terminal/gwt/client/VErrorMessage.java b/src/com/vaadin/terminal/gwt/client/VErrorMessage.java
index ba25dd23db..ba5d5a9d24 100644
--- a/src/com/vaadin/terminal/gwt/client/VErrorMessage.java
+++ b/src/com/vaadin/terminal/gwt/client/VErrorMessage.java
@@ -30,13 +30,18 @@ public class VErrorMessage extends FlowPanel {
if (child instanceof String) {
final String errorMessage = (String) child;
add(new HTML(errorMessage));
- } else if (child instanceof UIDL.XML) {
- final UIDL.XML xml = (UIDL.XML) child;
- add(new HTML(xml.getXMLAsString()));
} else {
- final VErrorMessage childError = new VErrorMessage();
- add(childError);
- childError.updateFromUIDL((UIDL) child);
+ try {
+ final VErrorMessage childError = new VErrorMessage();
+ childError.updateFromUIDL((UIDL) child);
+ add(childError);
+ } catch (Exception e) {
+ // TODO XML type error, check if this can even happen
+ // anymore??
+ final UIDL.XML xml = (UIDL.XML) child;
+ add(new HTML(xml.getXMLAsString()));
+
+ }
}
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/Icon.java b/src/com/vaadin/terminal/gwt/client/ui/Icon.java
index 1ee19c1d17..eba1a9bd78 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/Icon.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/Icon.java
@@ -10,13 +10,14 @@ import com.google.gwt.user.client.ui.UIObject;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
public class Icon extends UIObject {
+ public static final String CLASSNAME = "v-icon";
private final ApplicationConnection client;
private String myUri;
public Icon(ApplicationConnection client) {
setElement(DOM.createImg());
DOM.setElementProperty(getElement(), "alt", "");
- setStyleName("v-icon");
+ setStyleName(CLASSNAME);
this.client = client;
client.addPngFix(getElement());
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java b/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java
index d0c140dac0..dc3cd6b2e3 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java
@@ -68,6 +68,12 @@ public class VCustomComponent extends SimplePanel implements Container {
renderSpace.setWidth(getElement().getOffsetWidth());
renderSpace.setHeight(getElement().getOffsetHeight());
+ /*
+ * Needed to update client size if the size of this component has
+ * changed and the child uses relative size(s).
+ */
+ client.runDescendentsLayout(this);
+
rendering = false;
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
index 7e9cf96d72..e2f217267a 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
@@ -272,15 +272,31 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
c.cc.updateWidgetSize();
int newHeight = c.getHeight();
if (columnWidths[i] < oldWidths[i]
- && newHeight > minRowHeights[j]) {
+ && newHeight > minRowHeights[j]
+ && c.rowspan == 1) {
+ /*
+ * The width of this column was reduced and
+ * this affected the height. The height is
+ * now greater than the previously
+ * calculated minHeight for the row.
+ */
minRowHeights[j] = newHeight;
if (newHeight > rowHeights[j]) {
+ /*
+ * The new height is greater than the
+ * previously calculated rowHeight -> we
+ * need to recalculate heights later on
+ */
rowHeights[j] = newHeight;
heightChanged = true;
}
} else if (newHeight < minRowHeights[j]) {
- // need to recalculate new minimum height
- // for this row
+ /*
+ * The new height of the component is less
+ * than the previously calculated min row
+ * height. The min row height may be
+ * affected and must thus be recalculated
+ */
if (dirtyRows == null) {
dirtyRows = new HashSet<Integer>();
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java b/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
index 5bfaea9243..0e09c7a287 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
@@ -12,16 +12,20 @@ import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.HasHTML;
import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.ContainerResizedListener;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
public class VMenuBar extends Widget implements Paintable,
- CloseHandler<PopupPanel> {
+ CloseHandler<PopupPanel>, ContainerResizedListener {
/** Set the CSS class name to allow styling. */
public static final String CLASSNAME = "v-menubar";
@@ -32,8 +36,8 @@ public class VMenuBar extends Widget implements Paintable,
protected final VMenuBar hostReference = this;
protected String submenuIcon = null;
- protected boolean collapseItems = true;
protected CustomMenuItem moreItem = null;
+ protected VMenuBar collapsedRootItems;
// Construct an empty command to be used when the item has no command
// associated
@@ -45,9 +49,12 @@ public class VMenuBar extends Widget implements Paintable,
protected Element containerElement;
protected VOverlay popup;
protected VMenuBar visibleChildMenu;
+ protected boolean menuVisible = false;
protected VMenuBar parentMenu;
protected CustomMenuItem selected;
+ private Timer layoutTimer;
+
public VMenuBar() {
// Create an empty horizontal menubar
this(false);
@@ -67,23 +74,24 @@ public class VMenuBar extends Widget implements Paintable,
DOM.appendChild(table, tbody);
if (!subMenu) {
- setStyleName(CLASSNAME);
+ setStylePrimaryName(CLASSNAME);
Element tr = DOM.createTR();
DOM.appendChild(tbody, tr);
containerElement = tr;
} else {
- setStyleName(CLASSNAME + "-submenu");
+ setStylePrimaryName(CLASSNAME + "-submenu");
containerElement = tbody;
}
this.subMenu = subMenu;
- sinkEvents(Event.ONCLICK | Event.ONMOUSEOVER | Event.ONMOUSEOUT);
+ sinkEvents(Event.ONCLICK | Event.ONMOUSEOVER | Event.ONMOUSEOUT
+ | Event.ONLOAD);
}
/**
* This method must be implemented to update the client-side component from
* UIDL data received from server.
- *
+ *
* This method is called when the page is loaded for the first time, and
* every time UI changes in the component are received from the server.
*/
@@ -105,6 +113,7 @@ public class VMenuBar extends Widget implements Paintable,
UIDL options = uidl.getChildUIDL(0);
+ // FIXME remove in version 7
if (options.hasAttribute("submenuIcon")) {
submenuIcon = client.translateVaadinUri(uidl.getChildUIDL(0)
.getStringAttribute("submenuIcon"));
@@ -112,21 +121,27 @@ public class VMenuBar extends Widget implements Paintable,
submenuIcon = null;
}
- collapseItems = options.getBooleanAttribute("collapseItems");
-
- if (collapseItems) {
+ if (uidl.hasAttribute("width")) {
UIDL moreItemUIDL = options.getChildUIDL(0);
StringBuffer itemHTML = new StringBuffer();
if (moreItemUIDL.hasAttribute("icon")) {
itemHTML.append("<img src=\""
+ client.translateVaadinUri(moreItemUIDL
- .getStringAttribute("icon"))
- + "\" align=\"left\" />");
+ .getStringAttribute("icon")) + "\" class=\""
+ + Icon.CLASSNAME + "\" alt=\"\" />");
+ }
+
+ String moreItemText = moreItemUIDL.getStringAttribute("text");
+ if ("".equals(moreItemText)) {
+ moreItemText = "&#x25BA;";
}
- itemHTML.append(moreItemUIDL.getStringAttribute("text"));
+ itemHTML.append(moreItemText);
moreItem = new CustomMenuItem(itemHTML.toString(), emptyCommand);
+ collapsedRootItems = new VMenuBar(true);
+ moreItem.setSubMenu(collapsedRootItems);
+ moreItem.addStyleName(CLASSNAME + "-more-menuitem");
}
UIDL uidlItems = uidl.getChildUIDL(1);
@@ -142,45 +157,66 @@ public class VMenuBar extends Widget implements Paintable,
String itemText = item.getStringAttribute("text");
final int itemId = item.getIntAttribute("id");
- boolean itemHasCommand = item.getBooleanAttribute("command");
+ boolean itemHasCommand = item.hasAttribute("command");
// Construct html from the text and the optional icon
StringBuffer itemHTML = new StringBuffer();
+ Command cmd = null;
- if (item.hasAttribute("icon")) {
- itemHTML.append("<img src=\""
- + client.translateVaadinUri(item
- .getStringAttribute("icon"))
- + "\" align=\"left\" />");
- }
-
- itemHTML.append(itemText);
+ if (item.hasAttribute("separator")) {
+ itemHTML.append("<span>---</span>");
+ } else {
+ // Add submenu indicator
+ if (item.getChildCount() > 0) {
+ // FIXME For compatibility reasons: remove in version 7
+ String bgStyle = "";
+ if (submenuIcon != null) {
+ bgStyle = " style=\"background-image: url("
+ + submenuIcon
+ + "); text-indent: -999px; width: 1em;\"";
+ }
+ itemHTML.append("<span class=\"" + CLASSNAME
+ + "-submenu-indicator\"" + bgStyle
+ + ">&#x25BA;</span>");
+ }
- if (currentMenu != this && item.getChildCount() > 0
- && submenuIcon != null) {
- itemHTML.append("<img src=\"" + submenuIcon
- + "\" align=\"right\" />");
- }
+ if (item.hasAttribute("icon")) {
+ itemHTML
+ .append("<img src=\""
+ + client.translateVaadinUri(item
+ .getStringAttribute("icon"))
+ + "\" class=\"" + Icon.CLASSNAME
+ + "\" alt=\"\" />");
+ }
- Command cmd = null;
+ itemHTML.append(Util.escapeHTML(itemText));
- if (itemHasCommand) {
- // Construct a command that fires onMenuClick(int) with the
- // item's id-number
- cmd = new Command() {
- public void execute() {
- hostReference.onMenuClick(itemId);
- }
- };
+ if (itemHasCommand) {
+ // Construct a command that fires onMenuClick(int) with the
+ // item's id-number
+ cmd = new Command() {
+ public void execute() {
+ hostReference.onMenuClick(itemId);
+ }
+ };
+ }
}
currentItem = currentMenu.addItem(itemHTML.toString(), cmd);
+ currentItem.setSeparator(item.hasAttribute("separator"));
+ currentItem.setEnabled(!item.hasAttribute("disabled"));
if (item.getChildCount() > 0) {
menuStack.push(currentMenu);
iteratorStack.push(itr);
itr = item.getChildIterator();
currentMenu = new VMenuBar(true);
+ if (uidl.hasAttribute("style")) {
+ for (String style : uidl.getStringAttribute("style").split(
+ " ")) {
+ currentMenu.addStyleDependentName(style);
+ }
+ }
currentItem.setSubMenu(currentMenu);
}
@@ -190,54 +226,14 @@ public class VMenuBar extends Widget implements Paintable,
}
}// while
- // we might need to collapse the top-level menu
- // Only needed if there is more than 1 top level item
- // TODO and if width is defined
- if (collapseItems && getItems().size() > 1) {
-
- int topLevelWidth = 0;
+ iLayout();
- int ourWidth = getOffsetWidth();
-
- int i = 0;
- for (; i < getItems().size() && topLevelWidth < ourWidth; i++) {
- CustomMenuItem item = getItems().get(i);
- topLevelWidth += item.getOffsetWidth();
- }
-
- if (topLevelWidth > getOffsetWidth()) {
- ArrayList<CustomMenuItem> toBeCollapsed = new ArrayList<CustomMenuItem>();
- VMenuBar collapsed = new VMenuBar(true);
- for (int j = i - 2; j < getItems().size(); j++) {
- toBeCollapsed.add(getItems().get(j));
- }
-
- for (int j = 0; j < toBeCollapsed.size(); j++) {
- CustomMenuItem item = toBeCollapsed.get(j);
- removeItem(item);
-
- // it's ugly, but we have to insert the submenu icon
- if (item.getSubMenu() != null && submenuIcon != null) {
- StringBuffer itemText = new StringBuffer(item.getHTML());
- itemText.append("<img src=\"");
- itemText.append(submenuIcon);
- itemText.append("\" align=\"right\" />");
- item.setHTML(itemText.toString());
- }
-
- collapsed.addItem(item);
- }
-
- moreItem.setSubMenu(collapsed);
- addItem(moreItem);
- }
- }
}// updateFromUIDL
/**
* This is called by the items in the menu and it communicates the
* information to the server
- *
+ *
* @param clickedItemId
* id of the item that was clicked
*/
@@ -274,7 +270,7 @@ public class VMenuBar extends Widget implements Paintable,
/**
* Returns the containing element of the menu
- *
+ *
* @return
*/
public Element getContainingElement() {
@@ -283,23 +279,30 @@ public class VMenuBar extends Widget implements Paintable,
/**
* Returns a new child element to add an item to
- *
+ *
+ * @param index
+ * the index in which point to add a new element in a submenu. -1
+ * will add the new element as the last child (append)
+ *
* @return
*/
- public Element getNewChildElement() {
+ public Element getNewChildElement(int index) {
if (subMenu) {
Element tr = DOM.createTR();
- DOM.appendChild(getContainingElement(), tr);
+ if (index == -1) {
+ DOM.appendChild(getContainingElement(), tr);
+ } else {
+ DOM.insertChild(getContainingElement(), tr, index);
+ }
return tr;
} else {
return getContainingElement();
}
-
}
/**
* Add a new item to this menu
- *
+ *
* @param html
* items text
* @param cmd
@@ -314,19 +317,36 @@ public class VMenuBar extends Widget implements Paintable,
/**
* Add a new item to this menu
- *
+ *
* @param item
*/
public void addItem(CustomMenuItem item) {
- DOM.appendChild(getNewChildElement(), item.getElement());
+ if (items.contains(item)) {
+ return;
+ }
+ DOM.appendChild(getNewChildElement(-1), item.getElement());
item.setParentMenu(this);
item.setSelected(false);
items.add(item);
}
+ public void addItem(CustomMenuItem item, int index) {
+ if (items.contains(item)) {
+ return;
+ }
+ if (subMenu) {
+ DOM.appendChild(getNewChildElement(index), item.getElement());
+ } else {
+ DOM.insertChild(getNewChildElement(-1), item.getElement(), index);
+ }
+ item.setParentMenu(this);
+ item.setSelected(false);
+ items.add(index, item);
+ }
+
/**
* Remove the given item from this menu
- *
+ *
* @param item
*/
public void removeItem(CustomMenuItem item) {
@@ -348,6 +368,12 @@ public class VMenuBar extends Widget implements Paintable,
public void onBrowserEvent(Event e) {
super.onBrowserEvent(e);
+ // Handle onload events (icon loaded, size changes)
+ if (DOM.eventGetType(e) == Event.ONLOAD) {
+ requestLayout();
+ return;
+ }
+
Element targetElement = DOM.eventGetTarget(e);
CustomMenuItem targetItem = null;
for (int i = 0; i < items.size(); i++) {
@@ -361,11 +387,15 @@ public class VMenuBar extends Widget implements Paintable,
switch (DOM.eventGetType(e)) {
case Event.ONCLICK:
- itemClick(targetItem);
+ if (targetItem.isEnabled()) {
+ itemClick(targetItem);
+ }
break;
case Event.ONMOUSEOVER:
- itemOver(targetItem);
+ if (targetItem.isEnabled()) {
+ itemOver(targetItem);
+ }
break;
case Event.ONMOUSEOUT:
@@ -375,9 +405,22 @@ public class VMenuBar extends Widget implements Paintable,
}
}
+ private void requestLayout() {
+ if (layoutTimer == null) {
+ layoutTimer = new Timer() {
+ @Override
+ public void run() {
+ layoutTimer = null;
+ iLayout();
+ }
+ };
+ }
+ layoutTimer.schedule(100);
+ }
+
/**
* When an item is clicked
- *
+ *
* @param item
*/
public void itemClick(CustomMenuItem item) {
@@ -388,7 +431,8 @@ public class VMenuBar extends Widget implements Paintable,
visibleChildMenu.hideChildren();
}
- hideParents();
+ hideParents(true);
+ menuVisible = false;
DeferredCommand.addCommand(item.getCommand());
} else {
@@ -396,26 +440,31 @@ public class VMenuBar extends Widget implements Paintable,
&& item.getSubMenu() != visibleChildMenu) {
setSelected(item);
showChildMenu(item);
+ menuVisible = true;
+ } else if (!subMenu) {
+ setSelected(null);
+ hideChildren();
+ menuVisible = false;
}
}
}
/**
* When the user hovers the mouse over the item
- *
+ *
* @param item
*/
public void itemOver(CustomMenuItem item) {
- setSelected(item);
-
- boolean menuWasVisible = visibleChildMenu != null;
+ if ((subMenu || menuVisible) && !item.isSeparator()) {
+ setSelected(item);
+ }
- if (menuWasVisible && visibleChildMenu != item.getSubMenu()) {
+ if (menuVisible && visibleChildMenu != item.getSubMenu()
+ && popup != null) {
popup.hide();
- visibleChildMenu = null;
}
- if (item.getSubMenu() != null && (parentMenu != null || menuWasVisible)
+ if (menuVisible && item.getSubMenu() != null
&& visibleChildMenu != item.getSubMenu()) {
showChildMenu(item);
}
@@ -423,54 +472,78 @@ public class VMenuBar extends Widget implements Paintable,
/**
* When the mouse is moved away from an item
- *
+ *
* @param item
*/
public void itemOut(CustomMenuItem item) {
- if (visibleChildMenu != item.getSubMenu() || visibleChildMenu == null) {
+ if (visibleChildMenu != item.getSubMenu()) {
hideChildMenu(item);
setSelected(null);
+ } else if (visibleChildMenu == null) {
+ setSelected(null);
}
}
/**
* Shows the child menu of an item. The caller must ensure that the item has
* a submenu.
- *
+ *
* @param item
*/
public void showChildMenu(CustomMenuItem item) {
+ final int shadowSpace = 10;
+
popup = new VOverlay(true, false, true);
popup.setWidget(item.getSubMenu());
popup.addCloseHandler(this);
+ popup.addAutoHidePartner(item.getElement());
+ int left = 0;
+ int top = 0;
if (subMenu) {
- popup.setPopupPosition(item.getParentMenu().getAbsoluteLeft()
- + item.getParentMenu().getOffsetWidth(), item
- .getAbsoluteTop());
+ left = item.getParentMenu().getAbsoluteLeft()
+ + item.getParentMenu().getOffsetWidth();
+ top = item.getAbsoluteTop();
} else {
- popup.setPopupPosition(item.getAbsoluteLeft(), item.getParentMenu()
- .getAbsoluteTop()
- + item.getParentMenu().getOffsetHeight());
+ left = item.getAbsoluteLeft();
+ top = item.getParentMenu().getAbsoluteTop()
+ + item.getParentMenu().getOffsetHeight();
}
+ popup.setPopupPosition(left, top);
item.getSubMenu().onShow();
visibleChildMenu = item.getSubMenu();
item.getSubMenu().setParentMenu(this);
popup.show();
+
+ if (left + popup.getOffsetWidth() >= RootPanel.getBodyElement()
+ .getOffsetWidth()
+ - shadowSpace) {
+ if (subMenu) {
+ left = item.getParentMenu().getAbsoluteLeft()
+ - popup.getOffsetWidth() - shadowSpace;
+ } else {
+ left = RootPanel.getBodyElement().getOffsetWidth()
+ - popup.getOffsetWidth() - shadowSpace;
+ }
+ // Accommodate space for shadow
+ if (left < shadowSpace) {
+ left = shadowSpace;
+ }
+ popup.setPopupPosition(left, top);
+ }
}
/**
* Hides the submenu of an item
- *
+ *
* @param item
*/
public void hideChildMenu(CustomMenuItem item) {
if (visibleChildMenu != null
&& !(visibleChildMenu == item.getSubMenu())) {
popup.hide();
-
}
}
@@ -478,9 +551,25 @@ public class VMenuBar extends Widget implements Paintable,
* When the menu is shown.
*/
public void onShow() {
- if (!items.isEmpty()) {
- (items.get(0)).setSelected(true);
+ // remove possible previous selection
+ if (selected != null) {
+ selected.setSelected(false);
+ selected = null;
}
+ menuVisible = true;
+ }
+
+ /**
+ * Listener method, fired when this menu is closed
+ */
+ public void onClose(CloseEvent<PopupPanel> event) {
+ hideChildren();
+ if (event.isAutoClosed()) {
+ hideParents(true);
+ menuVisible = false;
+ }
+ visibleChildMenu = null;
+ popup = null;
}
/**
@@ -496,22 +585,22 @@ public class VMenuBar extends Widget implements Paintable,
/**
* Recursively hide all parent menus
*/
- public void hideParents() {
-
+ public void hideParents(boolean autoClosed) {
if (visibleChildMenu != null) {
popup.hide();
setSelected(null);
+ menuVisible = !autoClosed;
}
if (getParentMenu() != null) {
- getParentMenu().hideParents();
+ getParentMenu().hideParents(autoClosed);
}
}
/**
* Returns the parent menu of this menu, or null if this is the top-level
* menu
- *
+ *
* @return
*/
public VMenuBar getParentMenu() {
@@ -520,7 +609,7 @@ public class VMenuBar extends Widget implements Paintable,
/**
* Set the parent menu of this menu
- *
+ *
* @param parent
*/
public void setParentMenu(VMenuBar parent) {
@@ -530,7 +619,7 @@ public class VMenuBar extends Widget implements Paintable,
/**
* Returns the currently selected item of this menu, or null if nothing is
* selected
- *
+ *
* @return
*/
public CustomMenuItem getSelected() {
@@ -539,7 +628,7 @@ public class VMenuBar extends Widget implements Paintable,
/**
* Set the currently selected item of this menu
- *
+ *
* @param item
*/
public void setSelected(CustomMenuItem item) {
@@ -556,23 +645,9 @@ public class VMenuBar extends Widget implements Paintable,
}
/**
- * Listener method, fired when this menu is closed
- */
- public void onClose(CloseEvent<PopupPanel> event) {
- hideChildren();
- if (event.isAutoClosed()) {
- hideParents();
- }
- // setSelected(null);
- visibleChildMenu = null;
- popup = null;
-
- }
-
- /**
- *
+ *
* A class to hold information on menu items
- *
+ *
*/
private class CustomMenuItem extends UIObject implements HasHTML {
@@ -580,6 +655,8 @@ public class VMenuBar extends Widget implements Paintable,
protected Command command = null;
protected VMenuBar subMenu = null;
protected VMenuBar parentMenu = null;
+ protected boolean enabled = true;
+ protected boolean isSeparator = false;
public CustomMenuItem(String html, Command cmd) {
setElement(DOM.createTD());
@@ -588,11 +665,11 @@ public class VMenuBar extends Widget implements Paintable,
setCommand(cmd);
setSelected(false);
- addStyleName("menuitem");
+ setStylePrimaryName(CLASSNAME + "-menuitem");
}
public void setSelected(boolean selected) {
- if (selected) {
+ if (selected && !isSeparator) {
addStyleDependentName("selected");
} else {
removeStyleDependentName("selected");
@@ -642,8 +719,104 @@ public class VMenuBar extends Widget implements Paintable,
public void setText(String text) {
setHTML(text);
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ if (enabled) {
+ removeStyleDependentName("disabled");
+ } else {
+ addStyleDependentName("disabled");
+ }
+ }
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ private void setSeparator(boolean separator) {
+ isSeparator = separator;
+ if (separator) {
+ setStyleName(CLASSNAME + "-separator");
+ } else {
+ setStyleName(CLASSNAME + "-menuitem");
+ setEnabled(enabled);
+ }
+ }
+
+ public boolean isSeparator() {
+ return isSeparator;
+ }
+ }
+
+ /**
+ * @author Jouni Koivuviita / IT Mill Ltd.
+ */
+
+ public void iLayout() {
+ // Only collapse if there is more than one item in the root menu and the
+ // menu has an explicit size
+ if ((getItems().size() > 1 || collapsedRootItems.getItems().size() > 0)
+ && getElement().getStyle().getProperty("width") != null
+ && moreItem != null) {
+
+ // Measure the width of the "more" item
+ final boolean morePresent = getItems().contains(moreItem);
+ addItem(moreItem);
+ final int moreItemWidth = moreItem.getOffsetWidth();
+ if (!morePresent) {
+ removeItem(moreItem);
+ }
+
+ // Measure available space
+ int availableWidth = getElement().getClientWidth();
+ final int rootWidth = getElement().getFirstChildElement()
+ .getOffsetWidth();
+ int diff = availableWidth - rootWidth;
+
+ removeItem(moreItem);
+
+ if (diff < 0) {
+ // Too many items: collapse last items from root menu
+ final int widthNeeded = moreItemWidth - diff;
+ int widthReduced = 0;
+
+ while (widthReduced < widthNeeded && getItems().size() > 0) {
+ // Move last root menu item to collapsed menu
+ CustomMenuItem collapse = getItems().get(
+ getItems().size() - 1);
+ widthReduced += collapse.getOffsetWidth();
+ removeItem(collapse);
+ collapsedRootItems.addItem(collapse, 0);
+ }
+ } else if (collapsedRootItems.getItems().size() > 0) {
+ // Space available for items: expand first items from collapsed
+ // menu
+ int widthAvailable = diff + moreItemWidth;
+ int widthGrowth = 0;
+
+ while (widthAvailable > widthGrowth) {
+ // Move first item from collapsed menu to the root menu
+ CustomMenuItem expand = collapsedRootItems.getItems()
+ .get(0);
+ collapsedRootItems.removeItem(expand);
+ addItem(expand);
+ widthGrowth += expand.getOffsetWidth();
+ if (collapsedRootItems.getItems().size() > 0) {
+ widthAvailable -= moreItemWidth;
+ }
+ if (widthGrowth > widthAvailable) {
+ removeItem(expand);
+ collapsedRootItems.addItem(expand, 0);
+ } else {
+ widthAvailable = diff;
+ }
+ }
+ }
+ if (collapsedRootItems.getItems().size() > 0) {
+ addItem(moreItem);
+ }
}
}
-}// class VMenuBar
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java b/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java
index fb6831e31a..43f08b6a0c 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java
@@ -213,6 +213,7 @@ public class VOverlay extends PopupPanel {
zIndex = DOM.getStyleAttribute(getElement(), "zIndex");
} catch (Exception ignore) {
// Ignored, will cause no harm
+ zIndex = "1000";
}
if (zIndex == null) {
zIndex = "" + Z_INDEX;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java
index 9b74167689..0f269722de 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java
@@ -78,19 +78,36 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field,
public void setPosition(int offsetWidth, int offsetHeight) {
final int w = offsetWidth;
final int h = offsetHeight;
+ final int browserWindowWidth = Window.getClientWidth()
+ + Window.getScrollLeft();
+ final int browserWindowHeight = Window.getClientHeight()
+ + Window.getScrollTop();
int t = calendarToggle.getAbsoluteTop();
int l = calendarToggle.getAbsoluteLeft();
- if (l + w > Window.getClientWidth()
- + Window.getScrollLeft()) {
- l = Window.getClientWidth() + Window.getScrollLeft()
- - w;
+
+ // Add a little extra space to the right to avoid
+ // problems with IE6/IE7 scrollbars and to make it look
+ // nicer.
+ int extraSpace = 30;
+
+ boolean overflowRight = false;
+ if (l + +w + extraSpace > browserWindowWidth) {
+ overflowRight = true;
+ // Part of the popup is outside the browser window
+ // (to the right)
+ l = browserWindowWidth - w - extraSpace;
}
- if (t + h + calendarToggle.getOffsetHeight() + 30 > Window
- .getClientHeight()
- + Window.getScrollTop()) {
- t = Window.getClientHeight() + Window.getScrollTop()
- - h - calendarToggle.getOffsetHeight() - 30;
- l += calendarToggle.getOffsetWidth();
+
+ if (t + h + calendarToggle.getOffsetHeight() + 30 > browserWindowHeight) {
+ // Part of the popup is outside the browser window
+ // (below)
+ t = browserWindowHeight - h
+ - calendarToggle.getOffsetHeight() - 30;
+ if (!overflowRight) {
+ // Show to the right of the popup button unless we
+ // are in the lower right corner of the screen
+ l += calendarToggle.getOffsetWidth();
+ }
}
// fix size
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupView.java b/src/com/vaadin/terminal/gwt/client/ui/VPopupView.java
index 8e8a640e47..866ca99a0f 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VPopupView.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VPopupView.java
@@ -150,7 +150,18 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> {
popup.show();
}
- private void showPopup(final CustomPopup popup) {
+ /**
+ * Determines the correct position for a popup and displays the popup at
+ * that position.
+ *
+ * By default, the popup is shown centered relative to its host component,
+ * ensuring it is visible on the screen if possible.
+ *
+ * Can be overridden to customize the popup position.
+ *
+ * @param popup
+ */
+ protected void showPopup(final CustomPopup popup) {
int windowTop = RootPanel.get().getAbsoluteTop();
int windowLeft = RootPanel.get().getAbsoluteLeft();
int windowRight = windowLeft + RootPanel.get().getOffsetWidth();
@@ -207,7 +218,13 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> {
}
}-*/;
- private class CustomPopup extends VOverlay {
+ /**
+ * This class is only protected to enable overriding showPopup, and is
+ * currently not intended to be extended or otherwise used directly. Its API
+ * (other than it being a VOverlay) is to be considered private and
+ * potentially subject to change.
+ */
+ protected class CustomPopup extends VOverlay {
private Paintable popupComponentPaintable = null;
private Widget popupComponentWidget = null;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java b/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java
index 58d4d5c021..ab9f20bcc3 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java
@@ -21,6 +21,7 @@ public class VProgressIndicator extends Widget implements Paintable {
private final Poller poller;
private boolean indeterminate = false;
private boolean pollerSuspendedDueDetach;
+ private int interval;
public VProgressIndicator() {
setElement(DOM.createDiv());
@@ -33,12 +34,10 @@ public class VProgressIndicator extends Widget implements Paintable {
}
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- poller.cancel();
this.client = client;
+ if (!uidl.getBooleanAttribute("cached")) {
+ poller.cancel();
+ }
if (client.updateComponent(this, uidl, true)) {
return;
}
@@ -61,7 +60,8 @@ public class VProgressIndicator extends Widget implements Paintable {
}
if (!uidl.getBooleanAttribute("disabled")) {
- poller.scheduleRepeating(uidl.getIntAttribute("pollinginterval"));
+ interval = uidl.getIntAttribute("pollinginterval");
+ poller.scheduleRepeating(interval);
}
}
@@ -69,7 +69,7 @@ public class VProgressIndicator extends Widget implements Paintable {
protected void onAttach() {
super.onAttach();
if (pollerSuspendedDueDetach) {
- poller.run();
+ poller.scheduleRepeating(interval);
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java
index f73a2d4fc1..e66bf0fbc9 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java
@@ -36,6 +36,8 @@ public class VTabsheet extends VTabsheetBase {
private class TabSheetCaption extends VCaption {
private boolean hidden = false;
+ private boolean closable = false;
+ private Element closeButton;
TabSheetCaption() {
super(null, client);
@@ -57,12 +59,29 @@ public class VTabsheet extends VTabsheetBase {
client.registerTooltip(VTabsheet.this, getElement(), null);
}
- return super.updateCaption(uidl);
+ boolean ret = super.updateCaption(uidl);
+
+ setClosable(uidl.hasAttribute("closable"));
+
+ return ret;
}
@Override
public void onBrowserEvent(Event event) {
+ if (closable && event.getTypeInt() == Event.ONCLICK
+ && event.getEventTarget().cast() == closeButton) {
+ final String tabKey = tabKeys.get(tb.getTabIndex(this))
+ .toString();
+ if (!disabledTabKeys.contains(tabKey)) {
+ client.updateVariable(id, "close", tabKey, true);
+ event.stopPropagation();
+ event.preventDefault();
+ return;
+ }
+ }
+
super.onBrowserEvent(event);
+
if (event.getTypeInt() == Event.ONLOAD) {
// icon onloads may change total width of tabsheet
if (isDynamicWidth()) {
@@ -108,6 +127,35 @@ public class VTabsheet extends VTabsheetBase {
this.hidden = hidden;
}
+ public void setClosable(boolean closable) {
+ this.closable = closable;
+ if (closable && closeButton == null) {
+ closeButton = DOM.createSpan();
+ closeButton.setInnerText("x");
+ closeButton
+ .setClassName(VTabsheet.CLASSNAME + "-caption-close");
+ getElement().insertBefore(closeButton,
+ getElement().getLastChild());
+ } else if (!closable && closeButton != null) {
+ getElement().removeChild(closeButton);
+ closeButton = null;
+ }
+ if (closable) {
+ addStyleDependentName("closable");
+ } else {
+ removeStyleDependentName("closable");
+ }
+ }
+
+ @Override
+ public int getRequiredWidth() {
+ int width = super.getRequiredWidth();
+ if (closeButton != null) {
+ width += Util.getRequiredWidth(closeButton);
+ }
+ return width;
+ }
+
}
class TabBar extends ComplexPanel implements ClickHandler {
@@ -217,6 +265,10 @@ public class VTabsheet extends VTabsheetBase {
return (TabSheetCaption) getWidget(index);
}
+ public int getTabIndex(TabSheetCaption tab) {
+ return getChildren().indexOf(tab);
+ }
+
public void setVisible(int index, boolean visible) {
com.google.gwt.dom.client.Element e = getTab(index).getElement()
.getParentElement().getParentElement();
@@ -804,13 +856,13 @@ public class VTabsheet extends VTabsheetBase {
// Make sure scrollerIndex is valid
if (scrollerIndex > tb.getTabCount()) {
scrollerIndex = getNextVisibleTab(-1);
- } else if (tb.getTab(scrollerIndex).isHidden()) {
+ } else if (tb.getTabCount() > 0 && tb.getTab(scrollerIndex).isHidden()) {
scrollerIndex = getNextVisibleTab(scrollerIndex);
}
boolean scrolled = isScrolledTabs();
boolean clipped = isClippedTabs();
- if (tb.isVisible() && (scrolled || clipped)) {
+ if (tb.getTabCount() > 0 && tb.isVisible() && (scrolled || clipped)) {
DOM.setStyleAttribute(scroller, "display", "");
DOM.setElementProperty(scrollerPrev, "className",
SCROLLER_CLASSNAME + (scrolled ? "Prev" : "Prev-disabled"));
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java b/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
index 4403aede35..845a50e793 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
@@ -10,7 +10,9 @@ import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.TextBoxBase;
@@ -61,7 +63,8 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
protected VTextField(Element node) {
super(node);
- if (BrowserInfo.get().isIE()) {
+ if (BrowserInfo.get().getIEVersion() > 0
+ && BrowserInfo.get().getIEVersion() < 8) {
// Fixes IE margin problem (#2058)
DOM.setStyleAttribute(node, "marginTop", "-1px");
DOM.setStyleAttribute(node, "marginBottom", "-1px");
@@ -110,13 +113,32 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
: null;
setPrompting(inputPrompt != null && focusedTextField != this
&& (text == null || text.equals("")));
+
+ final String fieldValue;
if (prompting) {
- setText(inputPrompt);
+ fieldValue = inputPrompt;
addStyleDependentName(CLASSNAME_PROMPT);
} else {
- setText(text);
+ fieldValue = text;
removeStyleDependentName(CLASSNAME_PROMPT);
}
+ if (BrowserInfo.get().isGecko()) {
+ /*
+ * Gecko is really sluggish when updating input attached to dom.
+ * Some optimizations seems to work much better in Gecko if we
+ * update the actual content lazily when the rest of the DOM has
+ * stabilized. In tests, about ten times better performance is
+ * achieved with this optimization. See for eg. #2898
+ */
+ DeferredCommand.addCommand(new Command() {
+ public void execute() {
+ setText(fieldValue);
+ }
+ });
+ } else {
+ setText(fieldValue);
+ }
+
valueBeforeEdit = uidl.getStringVariable("text");
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java b/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java
index af04890881..ea91c5eac1 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java
@@ -1,330 +1,346 @@
-/*
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.Date;
-
-import com.google.gwt.event.dom.client.BlurEvent;
-import com.google.gwt.event.dom.client.BlurHandler;
-import com.google.gwt.event.dom.client.ChangeEvent;
-import com.google.gwt.event.dom.client.ChangeHandler;
-import com.google.gwt.event.dom.client.FocusEvent;
-import com.google.gwt.event.dom.client.FocusHandler;
-import com.google.gwt.i18n.client.DateTimeFormat;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.ui.TextBox;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.ClientExceptionHandler;
-import com.vaadin.terminal.gwt.client.ContainerResizedListener;
-import com.vaadin.terminal.gwt.client.Focusable;
-import com.vaadin.terminal.gwt.client.LocaleNotLoadedException;
-import com.vaadin.terminal.gwt.client.LocaleService;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-public class VTextualDate extends VDateField implements Paintable, Field,
- ChangeHandler, ContainerResizedListener, Focusable {
-
- private static final String PARSE_ERROR_CLASSNAME = CLASSNAME
- + "-parseerror";
-
- private final TextBox text;
-
- private String formatStr;
-
- private String width;
-
- private boolean needLayout;
-
- protected int fieldExtraWidth = -1;
-
- public VTextualDate() {
- super();
- text = new TextBox();
- // use normal textfield styles as a basis
- text.setStyleName(VTextField.CLASSNAME);
- // add datefield spesific style name also
- text.addStyleName(CLASSNAME + "-textfield");
- text.addChangeHandler(this);
- text.addFocusHandler(new FocusHandler() {
- public void onFocus(FocusEvent event) {
- text.addStyleName(VTextField.CLASSNAME + "-"
- + VTextField.CLASSNAME_FOCUS);
- }
- });
- text.addBlurHandler(new BlurHandler() {
- public void onBlur(BlurEvent event) {
- text.removeStyleName(VTextField.CLASSNAME + "-"
- + VTextField.CLASSNAME_FOCUS);
- }
- });
- add(text);
- }
-
- @Override
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-
- int origRes = currentResolution;
- super.updateFromUIDL(uidl, client);
- if (origRes != currentResolution) {
- // force recreating format string
- formatStr = null;
- }
- if (uidl.hasAttribute("format")) {
- formatStr = uidl.getStringAttribute("format");
- }
-
- buildDate();
- // not a FocusWidget -> needs own tabindex handling
- if (uidl.hasAttribute("tabindex")) {
- text.setTabIndex(uidl.getIntAttribute("tabindex"));
- }
-
- if (readonly) {
- text.addStyleDependentName("readonly");
- } else {
- text.removeStyleDependentName("readonly");
- }
- }
-
- protected String getFormatString() {
- if (formatStr == null) {
- if (currentResolution == RESOLUTION_YEAR) {
- formatStr = "yyyy"; // force full year
- } else {
-
- try {
- String frmString = LocaleService
- .getDateFormat(currentLocale);
- frmString = cleanFormat(frmString);
- String delim = LocaleService
- .getClockDelimiter(currentLocale);
-
- if (currentResolution >= RESOLUTION_HOUR) {
- if (dts.isTwelveHourClock()) {
- frmString += " hh";
- } else {
- frmString += " HH";
- }
- if (currentResolution >= RESOLUTION_MIN) {
- frmString += ":mm";
- if (currentResolution >= RESOLUTION_SEC) {
- frmString += ":ss";
- if (currentResolution >= RESOLUTION_MSEC) {
- frmString += ".SSS";
- }
- }
- }
- if (dts.isTwelveHourClock()) {
- frmString += " aaa";
- }
-
- }
-
- formatStr = frmString;
- } catch (LocaleNotLoadedException e) {
- ClientExceptionHandler.displayError(e);
- }
- }
- }
- return formatStr;
- }
-
- /**
- *
- */
- protected void buildDate() {
- removeStyleName(PARSE_ERROR_CLASSNAME);
- // Create the initial text for the textfield
- String dateText;
- if (date != null) {
- dateText = DateTimeFormat.getFormat(getFormatString()).format(date);
- } else {
- dateText = "";
- }
-
- text.setText(dateText);
- text.setEnabled(enabled);
- text.setReadOnly(readonly);
-
- if (readonly) {
- text.addStyleName("v-readonly");
- } else {
- text.removeStyleName("v-readonly");
- }
-
- }
-
- public void onChange(ChangeEvent event) {
- if (!text.getText().equals("")) {
- try {
- DateTimeFormat format = DateTimeFormat
- .getFormat(getFormatString());
- date = format.parse(text.getText());
- long stamp = date.getTime();
- if (stamp == 0) {
- // If date parsing fails in firefox the stamp will be 0
- date = null;
- addStyleName(PARSE_ERROR_CLASSNAME);
- } else {
- // remove possibly added invalid value indication
- removeStyleName(PARSE_ERROR_CLASSNAME);
- }
- } catch (final Exception e) {
- ClientExceptionHandler.displayError(e.getMessage());
-
- addStyleName(PARSE_ERROR_CLASSNAME);
- // this is a hack that may eventually be removed
- client.updateVariable(id, "lastInvalidDateString", text
- .getText(), false);
- date = null;
- }
- } else {
- date = null;
- // remove possibly added invalid value indication
- removeStyleName(PARSE_ERROR_CLASSNAME);
- }
- // always send the date string
- client.updateVariable(id, "dateString", text.getText(), false);
-
- if (date != null) {
- showingDate = new Date(date.getTime());
- }
-
- // Update variables
- // (only the smallest defining resolution needs to be
- // immediate)
- client.updateVariable(id, "year", date != null ? date.getYear() + 1900
- : -1, currentResolution == VDateField.RESOLUTION_YEAR
- && immediate);
- if (currentResolution >= VDateField.RESOLUTION_MONTH) {
- client.updateVariable(id, "month",
- date != null ? date.getMonth() + 1 : -1,
- currentResolution == VDateField.RESOLUTION_MONTH
- && immediate);
- }
- if (currentResolution >= VDateField.RESOLUTION_DAY) {
- client
- .updateVariable(id, "day", date != null ? date.getDate()
- : -1,
- currentResolution == VDateField.RESOLUTION_DAY
- && immediate);
- }
- if (currentResolution >= VDateField.RESOLUTION_HOUR) {
- client.updateVariable(id, "hour", date != null ? date.getHours()
- : -1, currentResolution == VDateField.RESOLUTION_HOUR
- && immediate);
- }
- if (currentResolution >= VDateField.RESOLUTION_MIN) {
- client.updateVariable(id, "min", date != null ? date.getMinutes()
- : -1, currentResolution == VDateField.RESOLUTION_MIN
- && immediate);
- }
- if (currentResolution >= VDateField.RESOLUTION_SEC) {
- client.updateVariable(id, "sec", date != null ? date.getSeconds()
- : -1, currentResolution == VDateField.RESOLUTION_SEC
- && immediate);
- }
- if (currentResolution == VDateField.RESOLUTION_MSEC) {
- client.updateVariable(id, "msec", date != null ? getMilliseconds()
- : -1, immediate);
- }
-
- }
-
- private String cleanFormat(String format) {
- // Remove unnecessary d & M if resolution is too low
- if (currentResolution < VDateField.RESOLUTION_DAY) {
- format = format.replaceAll("d", "");
- }
- if (currentResolution < VDateField.RESOLUTION_MONTH) {
- format = format.replaceAll("M", "");
- }
-
- // Remove unsupported patterns
- // TODO support for 'G', era designator (used at least in Japan)
- format = format.replaceAll("[GzZwWkK]", "");
-
- // Remove extra delimiters ('/' and '.')
- while (format.startsWith("/") || format.startsWith(".")
- || format.startsWith("-")) {
- format = format.substring(1);
- }
- while (format.endsWith("/") || format.endsWith(".")
- || format.endsWith("-")) {
- format = format.substring(0, format.length() - 1);
- }
-
- // Remove duplicate delimiters
- format = format.replaceAll("//", "/");
- format = format.replaceAll("\\.\\.", ".");
- format = format.replaceAll("--", "-");
-
- return format.trim();
- }
-
- @Override
- public void setWidth(String newWidth) {
- if (!"".equals(newWidth) && (width == null || !newWidth.equals(width))) {
- if (BrowserInfo.get().isIE6()) {
- // in IE6 cols ~ min-width
- DOM.setElementProperty(text.getElement(), "size", "1");
- }
- needLayout = true;
- width = newWidth;
- super.setWidth(width);
- iLayout();
- if (newWidth.indexOf("%") < 0) {
- needLayout = false;
- }
- } else {
- if ("".equals(newWidth) && width != null && !"".equals(width)) {
- if (BrowserInfo.get().isIE6()) {
- // revert IE6 hack
- DOM.setElementProperty(text.getElement(), "size", "");
- }
- super.setWidth("");
- needLayout = true;
- iLayout();
- needLayout = false;
- width = null;
- }
- }
- }
-
- /**
- * Returns pixels in x-axis reserved for other than textfield content.
- *
- * @return extra width in pixels
- */
- protected int getFieldExtraWidth() {
- if (fieldExtraWidth < 0) {
- text.setWidth("0");
- fieldExtraWidth = text.getOffsetWidth();
- if (BrowserInfo.get().isFF3()) {
- // Firefox somehow always leaves the INPUT element 2px wide
- fieldExtraWidth -= 2;
- }
- }
- return fieldExtraWidth;
- }
-
- public void updateWidth() {
- needLayout = true;
- fieldExtraWidth = -1;
- iLayout();
- }
-
- public void iLayout() {
- if (needLayout) {
- text.setWidth((getOffsetWidth() - getFieldExtraWidth()) + "px");
- }
- }
-
- public void focus() {
- text.setFocus(true);
- }
-}
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Date;
+
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
+import com.google.gwt.event.dom.client.ChangeEvent;
+import com.google.gwt.event.dom.client.ChangeHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.TextBox;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.ClientExceptionHandler;
+import com.vaadin.terminal.gwt.client.ContainerResizedListener;
+import com.vaadin.terminal.gwt.client.Focusable;
+import com.vaadin.terminal.gwt.client.LocaleNotLoadedException;
+import com.vaadin.terminal.gwt.client.LocaleService;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VTextualDate extends VDateField implements Paintable, Field,
+ ChangeHandler, ContainerResizedListener, Focusable {
+
+ private static final String PARSE_ERROR_CLASSNAME = CLASSNAME
+ + "-parseerror";
+
+ private final TextBox text;
+
+ private String formatStr;
+
+ private String width;
+
+ private boolean needLayout;
+
+ protected int fieldExtraWidth = -1;
+
+ private boolean lenient;
+
+ public VTextualDate() {
+
+ super();
+ text = new TextBox();
+ // use normal textfield styles as a basis
+ text.setStyleName(VTextField.CLASSNAME);
+ // add datefield spesific style name also
+ text.addStyleName(CLASSNAME + "-textfield");
+ text.addChangeHandler(this);
+ text.addFocusHandler(new FocusHandler() {
+ public void onFocus(FocusEvent event) {
+ text.addStyleName(VTextField.CLASSNAME + "-"
+ + VTextField.CLASSNAME_FOCUS);
+ }
+ });
+ text.addBlurHandler(new BlurHandler() {
+ public void onBlur(BlurEvent event) {
+ text.removeStyleName(VTextField.CLASSNAME + "-"
+ + VTextField.CLASSNAME_FOCUS);
+ }
+ });
+ add(text);
+ }
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+ int origRes = currentResolution;
+ super.updateFromUIDL(uidl, client);
+ if (origRes != currentResolution) {
+ // force recreating format string
+ formatStr = null;
+ }
+ if (uidl.hasAttribute("format")) {
+ formatStr = uidl.getStringAttribute("format");
+ }
+
+ lenient = !uidl.getBooleanAttribute("strict");
+
+ buildDate();
+ // not a FocusWidget -> needs own tabindex handling
+ if (uidl.hasAttribute("tabindex")) {
+ text.setTabIndex(uidl.getIntAttribute("tabindex"));
+ }
+
+ if (readonly) {
+ text.addStyleDependentName("readonly");
+ } else {
+ text.removeStyleDependentName("readonly");
+ }
+ }
+
+ protected String getFormatString() {
+ if (formatStr == null) {
+ if (currentResolution == RESOLUTION_YEAR) {
+ formatStr = "yyyy"; // force full year
+ } else {
+
+ try {
+ String frmString = LocaleService
+ .getDateFormat(currentLocale);
+ frmString = cleanFormat(frmString);
+ String delim = LocaleService
+ .getClockDelimiter(currentLocale);
+
+ if (currentResolution >= RESOLUTION_HOUR) {
+ if (dts.isTwelveHourClock()) {
+ frmString += " hh";
+ } else {
+ frmString += " HH";
+ }
+ if (currentResolution >= RESOLUTION_MIN) {
+ frmString += ":mm";
+ if (currentResolution >= RESOLUTION_SEC) {
+ frmString += ":ss";
+ if (currentResolution >= RESOLUTION_MSEC) {
+ frmString += ".SSS";
+ }
+ }
+ }
+ if (dts.isTwelveHourClock()) {
+ frmString += " aaa";
+ }
+
+ }
+
+ formatStr = frmString;
+ } catch (LocaleNotLoadedException e) {
+ ClientExceptionHandler.displayError(e);
+ }
+ }
+ }
+ return formatStr;
+ }
+
+ /**
+ *
+ */
+ protected void buildDate() {
+ removeStyleName(PARSE_ERROR_CLASSNAME);
+ // Create the initial text for the textfield
+ String dateText;
+ if (date != null) {
+ dateText = DateTimeFormat.getFormat(getFormatString()).format(date);
+ } else {
+ dateText = "";
+ }
+
+ text.setText(dateText);
+ text.setEnabled(enabled);
+ text.setReadOnly(readonly);
+
+ if (readonly) {
+ text.addStyleName("v-readonly");
+ } else {
+ text.removeStyleName("v-readonly");
+ }
+
+ }
+
+ public void onChange(ChangeEvent event) {
+ if (!text.getText().equals("")) {
+ try {
+ DateTimeFormat format = DateTimeFormat
+ .getFormat(getFormatString());
+ if (lenient) {
+ date = format.parse(text.getText());
+ if (date != null) {
+ // if date value was leniently parsed, normalize text
+ // presentation
+ text.setValue(DateTimeFormat.getFormat(
+ getFormatString()).format(date), false);
+ }
+ } else {
+ date = format.parseStrict(text.getText());
+ }
+
+ long stamp = date.getTime();
+ if (stamp == 0) {
+ // If date parsing fails in firefox the stamp will be 0
+ date = null;
+ addStyleName(PARSE_ERROR_CLASSNAME);
+ } else {
+ // remove possibly added invalid value indication
+ removeStyleName(PARSE_ERROR_CLASSNAME);
+ }
+ } catch (final Exception e) {
+ ClientExceptionHandler.displayError(e.getMessage());
+
+ addStyleName(PARSE_ERROR_CLASSNAME);
+ // this is a hack that may eventually be removed
+ client.updateVariable(id, "lastInvalidDateString", text
+ .getText(), false);
+ date = null;
+ }
+ } else {
+ date = null;
+ // remove possibly added invalid value indication
+ removeStyleName(PARSE_ERROR_CLASSNAME);
+ }
+ // always send the date string
+ client.updateVariable(id, "dateString", text.getText(), false);
+
+ if (date != null) {
+ showingDate = new Date(date.getTime());
+ }
+
+ // Update variables
+ // (only the smallest defining resolution needs to be
+ // immediate)
+ client.updateVariable(id, "year", date != null ? date.getYear() + 1900
+ : -1, currentResolution == VDateField.RESOLUTION_YEAR
+ && immediate);
+ if (currentResolution >= VDateField.RESOLUTION_MONTH) {
+ client.updateVariable(id, "month",
+ date != null ? date.getMonth() + 1 : -1,
+ currentResolution == VDateField.RESOLUTION_MONTH
+ && immediate);
+ }
+ if (currentResolution >= VDateField.RESOLUTION_DAY) {
+ client
+ .updateVariable(id, "day", date != null ? date.getDate()
+ : -1,
+ currentResolution == VDateField.RESOLUTION_DAY
+ && immediate);
+ }
+ if (currentResolution >= VDateField.RESOLUTION_HOUR) {
+ client.updateVariable(id, "hour", date != null ? date.getHours()
+ : -1, currentResolution == VDateField.RESOLUTION_HOUR
+ && immediate);
+ }
+ if (currentResolution >= VDateField.RESOLUTION_MIN) {
+ client.updateVariable(id, "min", date != null ? date.getMinutes()
+ : -1, currentResolution == VDateField.RESOLUTION_MIN
+ && immediate);
+ }
+ if (currentResolution >= VDateField.RESOLUTION_SEC) {
+ client.updateVariable(id, "sec", date != null ? date.getSeconds()
+ : -1, currentResolution == VDateField.RESOLUTION_SEC
+ && immediate);
+ }
+ if (currentResolution == VDateField.RESOLUTION_MSEC) {
+ client.updateVariable(id, "msec", date != null ? getMilliseconds()
+ : -1, immediate);
+ }
+
+ }
+
+ private String cleanFormat(String format) {
+ // Remove unnecessary d & M if resolution is too low
+ if (currentResolution < VDateField.RESOLUTION_DAY) {
+ format = format.replaceAll("d", "");
+ }
+ if (currentResolution < VDateField.RESOLUTION_MONTH) {
+ format = format.replaceAll("M", "");
+ }
+
+ // Remove unsupported patterns
+ // TODO support for 'G', era designator (used at least in Japan)
+ format = format.replaceAll("[GzZwWkK]", "");
+
+ // Remove extra delimiters ('/' and '.')
+ while (format.startsWith("/") || format.startsWith(".")
+ || format.startsWith("-")) {
+ format = format.substring(1);
+ }
+ while (format.endsWith("/") || format.endsWith(".")
+ || format.endsWith("-")) {
+ format = format.substring(0, format.length() - 1);
+ }
+
+ // Remove duplicate delimiters
+ format = format.replaceAll("//", "/");
+ format = format.replaceAll("\\.\\.", ".");
+ format = format.replaceAll("--", "-");
+
+ return format.trim();
+ }
+
+ @Override
+ public void setWidth(String newWidth) {
+ if (!"".equals(newWidth) && (width == null || !newWidth.equals(width))) {
+ if (BrowserInfo.get().isIE6()) {
+ // in IE6 cols ~ min-width
+ DOM.setElementProperty(text.getElement(), "size", "1");
+ }
+ needLayout = true;
+ width = newWidth;
+ super.setWidth(width);
+ iLayout();
+ if (newWidth.indexOf("%") < 0) {
+ needLayout = false;
+ }
+ } else {
+ if ("".equals(newWidth) && width != null && !"".equals(width)) {
+ if (BrowserInfo.get().isIE6()) {
+ // revert IE6 hack
+ DOM.setElementProperty(text.getElement(), "size", "");
+ }
+ super.setWidth("");
+ needLayout = true;
+ iLayout();
+ needLayout = false;
+ width = null;
+ }
+ }
+ }
+
+ /**
+ * Returns pixels in x-axis reserved for other than textfield content.
+ *
+ * @return extra width in pixels
+ */
+ protected int getFieldExtraWidth() {
+ if (fieldExtraWidth < 0) {
+ text.setWidth("0");
+ fieldExtraWidth = text.getOffsetWidth();
+ if (BrowserInfo.get().isFF3()) {
+ // Firefox somehow always leaves the INPUT element 2px wide
+ fieldExtraWidth -= 2;
+ }
+ }
+ return fieldExtraWidth;
+ }
+
+ public void updateWidth() {
+ needLayout = true;
+ fieldExtraWidth = -1;
+ iLayout();
+ }
+
+ public void iLayout() {
+ if (needLayout) {
+ text.setWidth((getOffsetWidth() - getFieldExtraWidth()) + "px");
+ }
+ }
+
+ public void focus() {
+ text.setFocus(true);
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VUpload.java b/src/com/vaadin/terminal/gwt/client/ui/VUpload.java
index 64b86c47b3..aded833138 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VUpload.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VUpload.java
@@ -122,8 +122,9 @@ public class VUpload extends FormPanel implements Paintable,
if (uidl.hasAttribute("disabled") || uidl.hasAttribute("readonly")) {
disableUpload();
- } else if (uidl.getBooleanAttribute("state")) {
- enableUploaod();
+ } else if (!uidl.getBooleanAttribute("state")) {
+ // Enable the button only if an upload is not in progress
+ enableUpload();
}
}
@@ -150,13 +151,17 @@ public class VUpload extends FormPanel implements Paintable,
protected void disableUpload() {
submitButton.setEnabled(false);
- // fu.getElement().setPropertyBoolean("disabled", true);
+ if (!submitted) {
+ // Cannot disable the fileupload while submitting or the file won't
+ // be submitted at all
+ fu.getElement().setPropertyBoolean("disabled", true);
+ }
enabled = false;
}
- protected void enableUploaod() {
+ protected void enableUpload() {
submitButton.setEnabled(true);
- // fu.getElement().setPropertyBoolean("disabled", false);
+ fu.getElement().setPropertyBoolean("disabled", false);
enabled = true;
}
@@ -169,7 +174,7 @@ public class VUpload extends FormPanel implements Paintable,
panel.remove(fu);
fu = new MyFileUpload();
fu.setName(paintableId + "_file");
- // fu.getElement().setPropertyBoolean("disabled", !enabled);
+ fu.getElement().setPropertyBoolean("disabled", !enabled);
panel.add(fu);
panel.add(submitButton);
if (immediate) {
@@ -189,7 +194,7 @@ public class VUpload extends FormPanel implements Paintable,
rebuildPanel();
submitted = false;
- enableUploaod();
+ enableUpload();
}
public void onSubmit(SubmitEvent event) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VView.java b/src/com/vaadin/terminal/gwt/client/ui/VView.java
index 35b411ff1b..bfa4a653bd 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VView.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VView.java
@@ -143,6 +143,21 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
$wnd.location.reload();
}-*/;
+ /**
+ * Evaluate the given script in the browser document.
+ *
+ * @param script
+ * Script to be executed.
+ */
+ private static native void eval(String script)
+ /*-{
+ try {
+ if (script == null) return;
+ $wnd.eval(script);
+ } catch (e) {
+ }
+ }-*/;
+
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
rendering = true;
@@ -263,6 +278,9 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
actionHandler = new ShortcutActionHandler(id, client);
}
actionHandler.updateActionMap(childUidl);
+ } else if (tag == "execJS") {
+ String script = childUidl.getStringAttribute("script");
+ eval(script);
} else if (tag == "notifications") {
for (final Iterator it = childUidl.getChildIterator(); it
.hasNext();) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java
index 90d31698ed..a2a64dcf5a 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java
@@ -39,19 +39,34 @@ import com.vaadin.terminal.gwt.client.VDebugConsole;
*/
public class VWindow extends VOverlay implements Container, ScrollListener {
- private static final int MIN_HEIGHT = 100;
+ /**
+ * Minimum allowed height of a window. This refers to the content area, not
+ * the outer borders.
+ */
+ private static final int MIN_CONTENT_AREA_HEIGHT = 100;
- private static final int MIN_WIDTH = 150;
+ /**
+ * Minimum allowed width of a window. This refers to the content area, not
+ * the outer borders.
+ */
+ private static final int MIN_CONTENT_AREA_WIDTH = 150;
private static ArrayList<VWindow> windowOrder = new ArrayList<VWindow>();
public static final String CLASSNAME = "v-window";
/**
+ * Difference between offsetWidth and inner width for the content area.
+ */
+ private int contentAreaBorderPadding = -1;
+ /**
* Pixels used by inner borders and paddings horizontally (calculated only
- * once)
+ * once). This is the difference between the width of the root element and
+ * the content area, such that if root element width is set to "XYZpx" the
+ * inner width (width-border-padding) of the content area is
+ * X-contentAreaRootDifference.
*/
- private int borderWidth = -1;
+ private int contentAreaToRootDifference = -1;
private static final int STACKING_OFFSET_PIXELS = 15;
@@ -120,8 +135,8 @@ public class VWindow extends VOverlay implements Container, ScrollListener {
// resizes the window.
boolean centered = false;
- private RenderSpace renderSpace = new RenderSpace(MIN_WIDTH, MIN_HEIGHT,
- true);
+ private RenderSpace renderSpace = new RenderSpace(MIN_CONTENT_AREA_WIDTH,
+ MIN_CONTENT_AREA_HEIGHT, true);
private String width;
@@ -129,6 +144,8 @@ public class VWindow extends VOverlay implements Container, ScrollListener {
private boolean immediate;
+ private Element wrapper, wrapper2;
+
public VWindow() {
super(false, false, true); // no autohide, not modal, shadow
// Different style of shadow for windows
@@ -198,10 +215,10 @@ public class VWindow extends VOverlay implements Container, ScrollListener {
DOM.sinkEvents(closeBox, Event.ONCLICK);
DOM.sinkEvents(contents, Event.ONCLICK);
- final Element wrapper = DOM.createDiv();
+ wrapper = DOM.createDiv();
DOM.setElementProperty(wrapper, "className", CLASSNAME + "-wrap");
- final Element wrapper2 = DOM.createDiv();
+ wrapper2 = DOM.createDiv();
DOM.setElementProperty(wrapper2, "className", CLASSNAME + "-wrap2");
DOM.sinkEvents(wrapper, Event.ONKEYDOWN);
@@ -439,39 +456,78 @@ public class VWindow extends VOverlay implements Container, ScrollListener {
client.updateVariable(id, "width", w, true);
}
+ Util.runWebkitOverflowAutoFix(contentPanel.getElement());
+
}
private void setNaturalWidth() {
/*
- * For some reason IE6 has title DIV set to width 100% which messes this
- * up. Also IE6 has a 0 wide element so we use the container element.
+ * Use max(layout width, window width) i.e layout content width or
+ * caption width. We remove the previous set width so the width is
+ * allowed to shrink. All widths are measured as outer sizes, i.e. the
+ * borderWidth is added to the content.
*/
- int naturalWidth;
+
+ DOM.setStyleAttribute(getElement(), "width", "");
+
+ String oldHeaderWidth = ""; // Only for IE6
if (BrowserInfo.get().isIE6()) {
- String headerW = headerText.getStyle().getProperty("width");
+ /*
+ * For some reason IE6 has title DIV set to width 100% which
+ * interferes with the header measuring. Also IE6 has width set to
+ * the contentPanel.
+ */
+ oldHeaderWidth = headerText.getStyle().getProperty("width");
+ DOM.setStyleAttribute(contentPanel.getElement(), "width", "auto");
+ DOM.setStyleAttribute(contentPanel.getElement(), "zoom", "1");
headerText.getStyle().setProperty("width", "auto");
- naturalWidth = getElement().getOffsetWidth();
- headerText.getStyle().setProperty("width", headerW);
- } else {
- // use max(layout width, window width)
- // i.e layout content width or caption width
- int lowidth = contentPanel.getElement().getScrollWidth()
- + getBorderWidth(); // layout does not know about border
- int elwidth = getElement().getOffsetWidth();
- naturalWidth = (lowidth > elwidth ? lowidth : elwidth);
+ }
+
+ // Content
+ int contentWidth = contentPanel.getElement().getScrollWidth();
+ contentWidth += getContentAreaToRootDifference();
+
+ // Window width (caption)
+ int windowCaptionWidth = getOffsetWidth();
+
+ int naturalWidth = (contentWidth > windowCaptionWidth ? contentWidth
+ : windowCaptionWidth);
+
+ if (BrowserInfo.get().isIE6()) {
+ headerText.getStyle().setProperty("width", oldHeaderWidth);
}
setWidth(naturalWidth + "px");
}
- private int getBorderWidth() {
- if (borderWidth < 0) {
- if (!isAttached()) {
- return 0;
- }
- borderWidth = Util.measureHorizontalPaddingAndBorder(contents, 4);
+ private int getContentAreaToRootDifference() {
+ if (contentAreaToRootDifference < 0) {
+ measure();
+ }
+ return contentAreaToRootDifference;
+ }
+
+ private int getContentAreaBorderPadding() {
+ if (contentAreaBorderPadding < 0) {
+ measure();
+ }
+ return contentAreaBorderPadding;
+ }
+
+ private void measure() {
+ if (!isAttached()) {
+ return;
}
- return borderWidth;
+
+ contentAreaBorderPadding = Util.measureHorizontalPaddingAndBorder(
+ contents, 4);
+ int wrapperPaddingBorder = Util.measureHorizontalPaddingAndBorder(
+ wrapper, 0)
+ + Util.measureHorizontalPaddingAndBorder(wrapper2, 0);
+
+ contentAreaToRootDifference = wrapperPaddingBorder
+ + contentAreaBorderPadding;
+
}
private void setReadOnly(boolean readonly) {
@@ -753,15 +809,45 @@ public class VWindow extends VOverlay implements Container, ScrollListener {
}
}
+ /**
+ * Checks if the cursor was inside the browser content area when the event
+ * happened.
+ *
+ * @param event
+ * The event to be checked
+ * @return true, if the cursor is inside the browser content area
+ *
+ * false, otherwise
+ */
+ private boolean cursorInsideBrowserContentArea(Event event) {
+ if (event.getClientX() < 0 || event.getClientY() < 0) {
+ // Outside to the left or above
+ return false;
+ }
+
+ if (event.getClientX() > Window.getClientWidth()
+ || event.getClientY() > Window.getClientHeight()) {
+ // Outside to the right or below
+ return false;
+ }
+
+ return true;
+ }
+
private void setSize(Event event, boolean updateVariables) {
+ if (!cursorInsideBrowserContentArea(event)) {
+ // Only drag while cursor is inside the browser client area
+ return;
+ }
+
int w = event.getScreenX() - startX + origW;
- if (w < MIN_WIDTH + getBorderWidth()) {
- w = MIN_WIDTH + getBorderWidth();
+ if (w < MIN_CONTENT_AREA_WIDTH + getContentAreaToRootDifference()) {
+ w = MIN_CONTENT_AREA_WIDTH + getContentAreaToRootDifference();
}
int h = event.getScreenY() - startY + origH;
- if (h < MIN_HEIGHT + getExtraHeight()) {
- h = MIN_HEIGHT + getExtraHeight();
+ if (h < MIN_CONTENT_AREA_HEIGHT + getExtraHeight()) {
+ h = MIN_CONTENT_AREA_HEIGHT + getExtraHeight();
}
setWidth(w + "px");
@@ -795,22 +881,37 @@ public class VWindow extends VOverlay implements Container, ScrollListener {
return;
}
if (width != null && !"".equals(width)) {
- int pixelWidth;
- // Convert non-pixel values to pixels
+ int rootPixelWidth = -1;
if (width.indexOf("px") < 0) {
+ /*
+ * Convert non-pixel values to pixels by setting the width and
+ * then measuring it. Updates the "width" variable with the
+ * pixel width.
+ */
DOM.setStyleAttribute(getElement(), "width", width);
- pixelWidth = getElement().getOffsetWidth();
- width = pixelWidth + "px";
+ rootPixelWidth = getElement().getOffsetWidth();
+ width = rootPixelWidth + "px";
+ } else {
+ rootPixelWidth = Integer.parseInt(width.substring(0, width
+ .indexOf("px")));
}
+
+ // "width" now contains the new width in pixels
+
if (BrowserInfo.get().isIE6()) {
getElement().getStyle().setProperty("overflow", "hidden");
}
+
+ // Apply the new pixel width
getElement().getStyle().setProperty("width", width);
- pixelWidth = getElement().getOffsetWidth() - getBorderWidth();
- if (pixelWidth < MIN_WIDTH) {
- pixelWidth = MIN_WIDTH;
- int rootWidth = pixelWidth + getBorderWidth();
+ // Caculate the inner width of the content area
+ int contentAreaInnerWidth = rootPixelWidth
+ - getContentAreaToRootDifference();
+ if (contentAreaInnerWidth < MIN_CONTENT_AREA_WIDTH) {
+ contentAreaInnerWidth = MIN_CONTENT_AREA_WIDTH;
+ int rootWidth = contentAreaInnerWidth
+ + getContentAreaToRootDifference();
DOM.setStyleAttribute(getElement(), "width", rootWidth + "px");
}
@@ -819,10 +920,10 @@ public class VWindow extends VOverlay implements Container, ScrollListener {
// appear, content flows out of window)
if (BrowserInfo.get().isIE6()) {
DOM.setStyleAttribute(contentPanel.getElement(), "width",
- pixelWidth + "px");
+ contentAreaInnerWidth + "px");
}
- renderSpace.setWidth(contents.getOffsetWidth() - getBorderWidth());
+ renderSpace.setWidth(contentAreaInnerWidth);
updateShadowSizeAndPosition();
}
@@ -843,8 +944,8 @@ public class VWindow extends VOverlay implements Container, ScrollListener {
if (height != null && !"".equals(height)) {
DOM.setStyleAttribute(getElement(), "height", height);
int pixels = getElement().getOffsetHeight() - getExtraHeight();
- if (pixels < MIN_HEIGHT) {
- pixels = MIN_HEIGHT;
+ if (pixels < MIN_CONTENT_AREA_HEIGHT) {
+ pixels = MIN_CONTENT_AREA_HEIGHT;
int rootHeight = pixels + getExtraHeight();
DOM.setStyleAttribute(getElement(), "height", (rootHeight)
+ "px");
@@ -892,9 +993,12 @@ public class VWindow extends VOverlay implements Container, ScrollListener {
case Event.ONMOUSEMOVE:
if (dragging) {
centered = false;
- final int x = DOM.eventGetScreenX(event) - startX + origX;
- final int y = DOM.eventGetScreenY(event) - startY + origY;
- setPopupPosition(x, y);
+ if (cursorInsideBrowserContentArea(event)) {
+ // Only drag while cursor is inside the browser client area
+ final int x = DOM.eventGetScreenX(event) - startX + origX;
+ final int y = DOM.eventGetScreenY(event) - startY + origY;
+ setPopupPosition(x, y);
+ }
DOM.eventPreventDefault(event);
}
break;
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
index 995ec384a1..5fe2bacfc9 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
@@ -45,11 +45,11 @@ import com.vaadin.ui.Window;
/**
* Abstract implementation of the ApplicationServlet which handles all
* communication between the client and the server.
- *
+ *
* It is possible to extend this class to provide own functionality but in most
* cases this is unnecessary.
- *
- *
+ *
+ *
* @author IT Mill Ltd.
* @version
* @VERSION@
@@ -146,7 +146,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Called by the servlet container to indicate to a servlet that the servlet
* is being placed into service.
- *
+ *
* @param servletConfig
* the object containing the servlet's configuration and
* initialization parameters
@@ -215,7 +215,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Gets an application property value.
- *
+ *
* @param parameterName
* the Name or the parameter.
* @return String value or null if not found
@@ -236,7 +236,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Gets an system property value.
- *
+ *
* @param parameterName
* the Name or the parameter.
* @return String value or null if not found
@@ -265,7 +265,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Gets an application or system property value.
- *
+ *
* @param parameterName
* the Name or the parameter.
* @param defaultValue
@@ -295,7 +295,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Returns true if the servlet is running in production mode. Production
* mode disables all debug facilities.
- *
+ *
* @return true if in production mode, false if in debug mode
*/
public boolean isProductionMode() {
@@ -305,7 +305,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Receives standard HTTP requests from the public service method and
* dispatches them.
- *
+ *
* @param request
* the object that contains the request the client made of the
* servlet.
@@ -469,7 +469,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* Send notification to client's application. Used to notify client of
* critical errors and session expiration due to long inactivity. Server has
* no knowledge of what application client refers to.
- *
+ *
* @param request
* the HTTP request instance.
* @param response
@@ -531,7 +531,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* Returns the application instance to be used for the request. If an
* existing instance is not found a new one is created or null is returned
* to indicate that the application is not available.
- *
+ *
* @param request
* @param requestType
* @return
@@ -596,7 +596,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Check if the request should create an application if an existing
* application is not found.
- *
+ *
* @param request
* @param requestType
* @return true if an application should be created, false otherwise
@@ -627,7 +627,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* Gets resource path using different implementations. Required to
* supporting different servlet container implementations (application
* servers).
- *
+ *
* @param servletContext
* @param path
* the resource path.
@@ -656,16 +656,16 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* processing, when a certain URI is requested. The handlers are invoked
* before any windows URIs are processed and if a DownloadStream is returned
* it is sent to the client.
- *
+ *
* @param stream
* the download stream.
- *
+ *
* @param request
* the HTTP request instance.
* @param response
* the HTTP response to write to.
* @throws IOException
- *
+ *
* @see com.vaadin.terminal.URIHandler
*/
@SuppressWarnings("unchecked")
@@ -737,7 +737,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
out.flush();
}
out.close();
-
+ data.close();
}
}
@@ -746,7 +746,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* Creates a new application and registers it into WebApplicationContext
* (aka session). This is not meant to be overridden. Override
* getNewApplication to create the application instance in a custom way.
- *
+ *
* @param request
* @return
* @throws ServletException
@@ -787,7 +787,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Returns the theme for given request/window
- *
+ *
* @param request
* @param window
* @return
@@ -818,7 +818,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Returns the default theme. Must never return null.
- *
+ *
* @return
*/
public static String getDefaultTheme() {
@@ -828,7 +828,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Calls URI handlers for the request. If an URI handler returns a
* DownloadStream the stream is passed to the client for downloading.
- *
+ *
* @param applicationManager
* @param window
* @param request
@@ -875,7 +875,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* Invalidate session (weird to have session if we're saying
* that it's expired, and worse: portal integration will fail
* since the session is not created by the portal.
- *
+ *
* Session must be invalidated before criticalNotification as it
* commits the response.
*/
@@ -931,7 +931,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Creates a new application for the given request.
- *
+ *
* @param request
* the HTTP request.
* @return A new Application instance.
@@ -942,7 +942,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Starts the application if it is not already running.
- *
+ *
* @param request
* @param application
* @param webApplicationContext
@@ -969,7 +969,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* Check if this is a request for a static resource and, if it is, serve the
* resource to the client. Returns true if a file was served and the request
* has been handled, false otherwise.
- *
+ *
* @param request
* @param response
* @return
@@ -1001,7 +1001,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Serve resources from VAADIN directory.
- *
+ *
* @param request
* @param response
* @throws IOException
@@ -1111,7 +1111,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Get system messages from the current application class
- *
+ *
* @return
*/
protected SystemMessages getSystemMessages() {
@@ -1147,10 +1147,10 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* Return the URL from where static files, e.g. the widgetset and the theme,
* are served. In a standard configuration the VAADIN folder inside the
* returned folder is what is used for widgetsets and themes.
- *
+ *
* The returned folder is usually the same as the context path and
* independent of the application.
- *
+ *
* @param request
* @return The location of static resources (should contain the VAADIN
* directory). Never ends with a slash (/).
@@ -1172,7 +1172,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* The default method to fetch static files location. This method does not
* check for request attribute {@value #REQUEST_VAADIN_STATIC_FILE_PATH}.
- *
+ *
* @param request
* @return
*/
@@ -1215,7 +1215,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Remove any heading or trailing "what" from the "string".
- *
+ *
* @param string
* @param what
* @return
@@ -1234,7 +1234,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Write a redirect response to the main page of the application.
- *
+ *
* @param request
* @param response
* @throws IOException
@@ -1264,7 +1264,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* {@link #writeAjaxPageHtmlMainDiv(BufferedWriter, String, String, String)}
* <li> {@link #writeAjaxPageHtmlBodyEnd(BufferedWriter)}
* </ul>
- *
+ *
* @param request
* the HTTP request.
* @param response
@@ -1376,10 +1376,10 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Get the URI for the application theme.
- *
+ *
* A portal-wide default theme is fetched from the portal shared resource
* directory (if any), other themes from the portlet.
- *
+ *
* @param themeName
* @param request
* @return
@@ -1409,7 +1409,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* Override this method if you want to add some custom html around around
* the div element into which the actual vaadin application will be
* rendered.
- *
+ *
* @param page
* @param appId
* @param classNames
@@ -1425,12 +1425,12 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
/**
- *
+ *
* * Method to write the script part of the page which loads needed vaadin
* scripts and themes.
* <p>
* Override this method if you want to add some custom html around scripts.
- *
+ *
* @param window
* @param themeName
* @param application
@@ -1458,8 +1458,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
// If no shared widgetset is specified, the default widgetset is
// assumed to be in the servlet/portlet itself.
requestWidgetset = getApplicationOrSystemProperty(
- PARAMETER_WIDGETSET,
- DEFAULT_WIDGETSET);
+ PARAMETER_WIDGETSET, DEFAULT_WIDGETSET);
}
String widgetset;
@@ -1573,14 +1572,14 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
/**
- *
+ *
* Method to open the body tag of the html kickstart page.
* <p>
* This method is responsible for closing the head tag and opening the body
* tag.
* <p>
* Override this method if you want to add some custom html to the page.
- *
+ *
* @param page
* @throws IOException
*/
@@ -1595,7 +1594,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* <p>
* Override this method if you want to add some custom html to the header of
* the page.
- *
+ *
* @param page
* @param title
* @param themeUri
@@ -1606,7 +1605,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
page
.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n");
page.write("<style type=\"text/css\">"
- + "html, body {height:100%;}</style>");
+ + "html, body {height:100%;margin:0;}</style>");
// Add favicon links
page
@@ -1627,7 +1626,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* <p>
* Override this method if you want to add some custom html to the very
* beginning of the page.
- *
+ *
* @param page
* @throws IOException
*/
@@ -1647,7 +1646,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* Method to set http request headers for the Vaadin kickstart page.
* <p>
* Override this method if you need to customize http headers of the page.
- *
+ *
* @param response
*/
protected void setAjaxPageHeaders(HttpServletResponse response) {
@@ -1668,7 +1667,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Gets the current application URL from request.
- *
+ *
* @param request
* the HTTP request.
* @throws MalformedURLException
@@ -1708,7 +1707,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Gets the existing application for given request. Looks for application
* instance for given request based on the requested URL.
- *
+ *
* @param request
* the HTTP request.
* @param allowSessionCreation
@@ -1768,7 +1767,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Ends the application.
- *
+ *
* @param request
* the HTTP request.
* @param response
@@ -1799,7 +1798,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Gets the existing application or create a new one. Get a window within an
* application based on the requested URI.
- *
+ *
* @param request
* the HTTP Request.
* @param application
@@ -1845,7 +1844,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Returns the path info; note that this _can_ be different than
* request.getPathInfo() (e.g application runner).
- *
+ *
* @param request
* @return
*/
@@ -1855,7 +1854,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Gets relative location of a theme resource.
- *
+ *
* @param theme
* the Theme name.
* @param resource
@@ -1902,7 +1901,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Gets the contained throwable.
- *
+ *
* @see com.vaadin.terminal.Terminal.ErrorEvent#getThrowable()
*/
public Throwable getThrowable() {
@@ -1911,7 +1910,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Gets the source ParameterHandler.
- *
+ *
* @see com.vaadin.terminal.ParameterHandler.ErrorEvent#getParameterHandler()
*/
public ParameterHandler getParameterHandler() {
@@ -1931,7 +1930,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
private final Throwable throwable;
/**
- *
+ *
* @param owner
* @param throwable
*/
@@ -1942,7 +1941,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Gets the contained throwable.
- *
+ *
* @see com.vaadin.terminal.Terminal.ErrorEvent#getThrowable()
*/
public Throwable getThrowable() {
@@ -1951,7 +1950,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/**
* Gets the source URIHandler.
- *
+ *
* @see com.vaadin.terminal.URIHandler.ErrorEvent#getURIHandler()
*/
public URIHandler getURIHandler() {
diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java b/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java
index 8ffd7b3f16..aeb1b50c9c 100644
--- a/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java
+++ b/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java
@@ -19,7 +19,7 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet {
* request.
*/
private String[] defaultPackages;
- private HttpServletRequest request;
+ private ThreadLocal<HttpServletRequest> request = new ThreadLocal<HttpServletRequest>();
@Override
public void init(ServletConfig servletConfig) throws ServletException {
@@ -34,9 +34,9 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet {
@Override
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
- this.request = request;
+ this.request.set(request);
super.service(request, response);
- this.request = null;
+ this.request.set(null);
}
@Override
@@ -150,25 +150,30 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet {
Class<? extends Application> appClass = null;
- String baseName = getApplicationRunnerApplicationClassName(request);
+ String baseName = getApplicationRunnerApplicationClassName(request
+ .get());
try {
appClass = (Class<? extends Application>) getClass()
.getClassLoader().loadClass(baseName);
return appClass;
} catch (Exception e) {
//
- for (int i = 0; i < defaultPackages.length; i++) {
- try {
- appClass = (Class<? extends Application>) getClass()
- .getClassLoader().loadClass(
- defaultPackages[i] + "." + baseName);
- } catch (Exception e2) {
- // TODO: handle exception
- }
- if (appClass != null) {
- return appClass;
+ if (defaultPackages != null) {
+ for (int i = 0; i < defaultPackages.length; i++) {
+ try {
+ appClass = (Class<? extends Application>) getClass()
+ .getClassLoader().loadClass(
+ defaultPackages[i] + "." + baseName);
+ } catch (Exception e2) {
+ // TODO: handle exception
+ e2.printStackTrace();
+ }
+ if (appClass != null) {
+ return appClass;
+ }
}
}
+
}
throw new ClassNotFoundException();
diff --git a/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java b/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java
index 304282fd9f..e49c95d905 100644
--- a/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java
+++ b/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java
@@ -36,7 +36,8 @@ import com.vaadin.service.ApplicationContext;
public class WebApplicationContext implements ApplicationContext,
HttpSessionBindingListener, Serializable {
- protected List<TransactionListener> listeners;
+ protected List<TransactionListener> listeners = Collections
+ .synchronizedList(new LinkedList<TransactionListener>());
protected transient HttpSession session;
@@ -87,7 +88,7 @@ public class WebApplicationContext implements ApplicationContext,
}
/**
- * Gets the application context for HttpSession.
+ * Gets the application context for an HttpSession.
*
* @param session
* the HTTP session.
@@ -108,70 +109,68 @@ public class WebApplicationContext implements ApplicationContext,
}
/**
- * Adds the transaction listener to this context.
+ * Adds a transaction listener to this context. The transaction listener is
+ * called before and after each each HTTP request related to this session
+ * except when serving static resources.
+ *
*
* @see com.vaadin.service.ApplicationContext#addTransactionListener(com.vaadin.service.ApplicationContext.TransactionListener)
*/
public void addTransactionListener(TransactionListener listener) {
- if (listeners == null) {
- listeners = new LinkedList<TransactionListener>();
- }
listeners.add(listener);
}
/**
- * Removes the transaction listener from this context.
+ * Removes a transaction listener from this context. The transaction
+ * listener is called before and after each each HTTP request related to
+ * this session except when serving static resources.
*
* @see com.vaadin.service.ApplicationContext#removeTransactionListener(com.vaadin.service.ApplicationContext.TransactionListener)
*/
public void removeTransactionListener(TransactionListener listener) {
- if (listeners != null) {
- listeners.remove(listener);
- }
+ listeners.remove(listener);
}
/**
- * Notifies the transaction start.
+ * Sends a notification that a transaction is starting.
*
* @param application
+ * The application associated with the transaction.
* @param request
- * the HTTP request.
+ * the HTTP request that triggered the transaction.
*/
protected void startTransaction(Application application,
HttpServletRequest request) {
- if (listeners == null) {
- return;
- }
- for (final Iterator i = listeners.iterator(); i.hasNext();) {
- ((ApplicationContext.TransactionListener) i.next())
- .transactionStart(application, request);
+ synchronized (listeners) {
+ for (TransactionListener listener : listeners) {
+ listener.transactionStart(application, request);
+ }
}
}
/**
- * Notifies the transaction end.
+ * Sends a notification that a transaction has ended.
*
* @param application
+ * The application associated with the transaction.
* @param request
- * the HTTP request.
+ * the HTTP request that triggered the transaction.
*/
protected void endTransaction(Application application,
HttpServletRequest request) {
- if (listeners == null) {
- return;
- }
-
LinkedList<Exception> exceptions = null;
- for (final Iterator i = listeners.iterator(); i.hasNext();) {
- try {
- ((ApplicationContext.TransactionListener) i.next())
- .transactionEnd(application, request);
- } catch (final RuntimeException t) {
- if (exceptions == null) {
- exceptions = new LinkedList<Exception>();
+
+ synchronized (listeners) {
+ for (TransactionListener listener : listeners) {
+ try {
+ listener.transactionEnd(application, request);
+ } catch (final RuntimeException t) {
+ if (exceptions == null) {
+ exceptions = new LinkedList<Exception>();
+ }
+ exceptions.add(t);
}
- exceptions.add(t);
}
}
diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java b/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java
index 269d911ad1..29e92fb625 100644
--- a/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java
+++ b/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java
@@ -41,7 +41,7 @@ import com.vaadin.ui.ClientWidget;
* appropriate monkey code for gwt directly in annotation processor and get rid
* of {@link WidgetMapGenerator}. Using annotation processor might be a good
* idea when dropping Java 1.5 support (integrated to javac in 6).
- *
+ *
*/
public class ClassPathExplorer {
private final static FileFilter DIRECTORIES_ONLY = new FileFilter() {
@@ -75,7 +75,7 @@ public class ClassPathExplorer {
/**
* Finds available widgetset names.
- *
+ *
* @return
*/
public static Map<String, URL> getAvailableWidgetSets() {
@@ -133,6 +133,10 @@ public class ClassPathExplorer {
JarFile jarFile = conn.getJarFile();
Manifest manifest = jarFile.getManifest();
+ if (manifest == null) {
+ // No manifest so this is not a Vaadin Add-on
+ return;
+ }
String value = manifest.getMainAttributes().getValue(
"Vaadin-Widgetsets");
if (value != null) {
@@ -218,10 +222,13 @@ public class ClassPathExplorer {
System.out.println(url);
JarFile jarFile = conn.getJarFile();
Manifest manifest = jarFile.getManifest();
- Attributes mainAttributes = manifest.getMainAttributes();
- if (mainAttributes.getValue("Vaadin-Widgetsets") != null) {
- System.err.println("Accepted jar file" + url);
- return true;
+ if (manifest != null) {
+ Attributes mainAttributes = manifest
+ .getMainAttributes();
+ if (mainAttributes.getValue("Vaadin-Widgetsets") != null) {
+ System.err.println("Accepted jar file" + url);
+ return true;
+ }
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
@@ -238,7 +245,7 @@ public class ClassPathExplorer {
/**
* Recursively add subdirectories and jar files to classpathlocations
- *
+ *
* @param name
* @param file
* @param locations
@@ -374,12 +381,12 @@ public class ClassPathExplorer {
/**
* Find and return the default source directory where to create new
* widgetsets.
- *
+ *
* Return the first directory (not a JAR file etc.) on the classpath by
* default.
- *
+ *
* TODO this could be done better...
- *
+ *
* @return URL
*/
public static URL getDefaultSourceDirectory() {
diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetSetBuilder.java b/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetSetBuilder.java
index d849c85fc7..2278488c1a 100644
--- a/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetSetBuilder.java
+++ b/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetSetBuilder.java
@@ -20,6 +20,11 @@ import java.util.regex.Pattern;
/**
* Helper class to update widgetsets GWT module configuration file. Can be used
* command line or via IDE tools.
+ *
+ * <p>
+ * If module definition file contains text "WS Compiler: manually edited", tool
+ * will skip editing file.
+ *
*/
public class WidgetSetBuilder {
@@ -60,38 +65,62 @@ public class WidgetSetBuilder {
+ "Google Web Toolkit 1.7.0//EN\" \"http://google"
+ "-web-toolkit.googlecode.com/svn/tags/1.7.0/dis"
+ "tro-source/core/src/gwt-module.dtd\">\n");
- printStream.print("<module>\n\n</module>\n");
+ printStream.print("<module>\n");
+ printStream
+ .print(" <!--\n"
+ + " Uncomment the following to compile the widgetset for one browser only.\n"
+ + " This can reduce the GWT compilation time significantly when debugging.\n"
+ + " The line should be commented out before deployment to production\n"
+ + " environments.\n\n"
+ + " Multiple browsers can be specified for GWT 1.7 as a comma separated\n"
+ + " list. The supported user agents at the moment of writing were:\n"
+ + " ie6,ie8,gecko,gecko1_8,safari,opera\n\n"
+ + " The value gecko is used for Firefox 3 and later, gecko1_8 is for\n"
+ + " Firefox 2 and safari is used for webkit based browsers including\n"
+ + " Google Chrome.\n"
+ + " -->\n"
+ + " <!-- <set-property name=\"user.agent\" value=\"gecko\"/> -->\n");
+ printStream.print("\n</module>\n");
printStream.close();
changed = true;
}
String content = readFile(widgetsetFile);
- String originalContent = content;
-
- Collection<String> oldInheritedWidgetsets = getCurrentWidgetSets(content);
-
- // add widgetsets that do not exist
- for (String ws : availableWidgetSets.keySet()) {
- if (ws.equals(widgetset)) {
- // do not inherit the module itself
- continue;
+ if (isEditable(content)) {
+ String originalContent = content;
+
+ Collection<String> oldInheritedWidgetsets = getCurrentWidgetSets(content);
+
+ // add widgetsets that do not exist
+ for (String ws : availableWidgetSets.keySet()) {
+ if (ws.equals(widgetset)) {
+ // do not inherit the module itself
+ continue;
+ }
+ if (!oldInheritedWidgetsets.contains(ws)) {
+ content = addWidgetSet(ws, content);
+ }
}
- if (!oldInheritedWidgetsets.contains(ws)) {
- content = addWidgetSet(ws, content);
+
+ for (String ws : oldInheritedWidgetsets) {
+ if (!availableWidgetSets.containsKey(ws)) {
+ // widgetset not available in classpath
+ content = removeWidgetSet(ws, content);
+ }
}
- }
- for (String ws : oldInheritedWidgetsets) {
- if (!availableWidgetSets.containsKey(ws)) {
- // widgetset not available in classpath
- content = removeWidgetSet(ws, content);
+ changed = changed || !content.equals(originalContent);
+ if (changed) {
+ commitChanges(widgetsetfilename, content);
}
+ } else {
+ System.out
+ .println("Widgetset is manually edited. Skipping updates.");
}
+ }
- changed = changed || !content.equals(originalContent);
- if (changed) {
- commitChanges(widgetsetfilename, content);
- }
+ private static boolean isEditable(String content) {
+ return !content.contains("WS Compiler: manually edited");
}
private static String removeWidgetSet(String ws, String content) {
@@ -135,6 +164,7 @@ public class WidgetSetBuilder {
sb.append(line);
sb.append("\n");
}
+ fi.close();
return sb.toString();
}
diff --git a/src/com/vaadin/ui/Button.java b/src/com/vaadin/ui/Button.java
index 6801bfa176..3ed50b2d42 100644
--- a/src/com/vaadin/ui/Button.java
+++ b/src/com/vaadin/ui/Button.java
@@ -36,7 +36,7 @@ public class Button extends AbstractField {
*
*/
public Button() {
- setValue(new Boolean(false));
+ setValue(Boolean.FALSE);
setSwitchMode(false);
}
@@ -96,7 +96,7 @@ public class Button extends AbstractField {
*/
public Button(String caption, boolean initialState) {
setCaption(caption);
- setValue(new Boolean(initialState));
+ setValue(Boolean.valueOf(initialState));
setSwitchMode(true);
}
@@ -167,7 +167,7 @@ public class Button extends AbstractField {
// If the button is true for some reason, release it
if (oldValue.booleanValue()) {
- setValue(new Boolean(false));
+ setValue(Boolean.FALSE);
}
}
}
@@ -194,7 +194,7 @@ public class Button extends AbstractField {
if (!switchMode) {
setImmediate(true);
if (booleanValue()) {
- setValue(new Boolean(false));
+ setValue(Boolean.FALSE);
}
}
}
diff --git a/src/com/vaadin/ui/DateField.java b/src/com/vaadin/ui/DateField.java
index 69d6108152..425040a016 100644
--- a/src/com/vaadin/ui/DateField.java
+++ b/src/com/vaadin/ui/DateField.java
@@ -116,6 +116,8 @@ public class DateField extends AbstractField {
*/
private String dateString;
+ private boolean lenient = false;
+
/* Constructors */
/**
@@ -202,6 +204,10 @@ public class DateField extends AbstractField {
target.addAttribute("format", dateFormat);
}
+ if (!isLenient()) {
+ target.addAttribute("strict", true);
+ }
+
target.addAttribute("type", type);
// Gets the calendar
@@ -332,13 +338,13 @@ public class DateField extends AbstractField {
newDate = cal.getTime();
}
- if (newDate != oldDate
+ if (newDate == null && dateString != null && !"".equals(dateString)
+ && !dateString.equals(oldDateString)) {
+ setValue(handleUnparsableDateString(dateString));
+ } else if (newDate != oldDate
&& (newDate == null || !newDate.equals(oldDate))) {
setValue(newDate, true); // Don't require a repaint, client
// updates itself
- } else if (dateString != null && !"".equals(dateString)
- && !dateString.equals(oldDateString)) {
- setValue(handleUnparsableDateString(dateString));
}
}
}
@@ -511,4 +517,32 @@ public class DateField extends AbstractField {
return dateFormat;
}
+ /**
+ * Specifies whether or not date/time interpretation in component is to be
+ * lenient.
+ *
+ * @see Calendar#setLenient(boolean)
+ * @see #isLenient()
+ *
+ * @param lenient
+ * true if the lenient mode is to be turned on; false if it is to
+ * be turned off.
+ */
+ public void setLenient(boolean lenient) {
+ this.lenient = lenient;
+ requestRepaint();
+ }
+
+ /**
+ * Specifies whether or not date/time interpretation is to be lenient.
+ *
+ * @see #setLenient(boolean)
+ *
+ * @return true if the interpretation mode of this calendar is lenient;
+ * false otherwise.
+ */
+ public boolean isLenient() {
+ return lenient;
+ }
+
}
diff --git a/src/com/vaadin/ui/LoginForm.java b/src/com/vaadin/ui/LoginForm.java
index 33ee670f4b..76c567dc5e 100644
--- a/src/com/vaadin/ui/LoginForm.java
+++ b/src/com/vaadin/ui/LoginForm.java
@@ -161,12 +161,14 @@ public class LoginForm extends CustomComponent {
+ "document.getElementsByTagName('head')[0].appendChild(stylesheet);\n"
+ "}"
+ "}\n"
+ + "function submitOnEnter(e) { var keycode = e.keyCode || e.which;"
+ + " if (keycode == 13) {document.forms[0].submit();} } \n"
+ "</script>"
+ "</head><body onload='setTarget();' style='margin:0;padding:0; background:transparent;' class=\"v-generated-body\">"
+ "<div class='v-app v-app-loginpage' style=\"background:transparent;\">"
+ "<iframe name='logintarget' style='width:0;height:0;"
+ "border:0;margin:0;padding:0;'></iframe>"
- + "<form id='loginf' target='logintarget'>"
+ + "<form id='loginf' target='logintarget' onkeypress=\"submitOnEnter(event)\">"
+ "<div>Username</div><div >"
+ "<input class='v-textfield' style='display:block;' type='text' name='username'></div>"
+ "<div>Password</div>"
diff --git a/src/com/vaadin/ui/MenuBar.java b/src/com/vaadin/ui/MenuBar.java
index 30049431d3..5715e230c4 100644
--- a/src/com/vaadin/ui/MenuBar.java
+++ b/src/com/vaadin/ui/MenuBar.java
@@ -29,8 +29,20 @@ public class MenuBar extends AbstractComponent {
// Number of items in this menu
private static int numberOfItems = 0;
+ /**
+ * @deprecated
+ * @see #setCollapse(boolean)
+ */
+ @Deprecated
private boolean collapseItems;
+
+ /**
+ * @deprecated
+ * @see #setSubmenuIcon(Resource)
+ */
+ @Deprecated
private Resource submenuIcon;
+
private MenuItem moreItem;
/** Paint (serialise) the component for the client. */
@@ -49,9 +61,7 @@ public class MenuBar extends AbstractComponent {
target.addAttribute("submenuIcon", submenuIcon);
}
- target.addAttribute("collapseItems", collapseItems);
-
- if (collapseItems) {
+ if (getWidth() > -1) {
target.startTag("moreItem");
target.addAttribute("text", moreItem.getText());
if (moreItem.getIcon() != null) {
@@ -69,31 +79,43 @@ public class MenuBar extends AbstractComponent {
while (itr.hasNext()) {
MenuItem item = itr.next();
+ if (!item.isVisible()) {
+ continue;
+ }
target.startTag("item");
-
- target.addAttribute("text", item.getText());
target.addAttribute("id", item.getId());
- Command command = item.getCommand();
- if (command != null) {
- target.addAttribute("command", true);
+ if (item.isSeparator()) {
+ target.addAttribute("separator", true);
+ target.endTag("item");
} else {
- target.addAttribute("command", false);
- }
+ target.addAttribute("text", item.getText());
- Resource icon = item.getIcon();
- if (icon != null) {
- target.addAttribute("icon", icon);
- }
+ Command command = item.getCommand();
+ if (command != null) {
+ target.addAttribute("command", true);
+ }
+
+ Resource icon = item.getIcon();
+ if (icon != null) {
+ target.addAttribute("icon", icon);
+ }
+
+ if (!item.isEnabled()) {
+ target.addAttribute("disabled", true);
+ }
- if (item.hasChildren()) {
- iteratorStack.push(itr); // For later use
+ if (item.hasChildren()) {
+ iteratorStack.push(itr); // For later use
+
+ // Go through the children
+ itr = item.getChildren().iterator();
+ } else {
+ target.endTag("item"); // Item had no children, end
+ // description
+ }
- // Go through the children
- itr = item.getChildren().iterator();
- } else {
- target.endTag("item"); // Item had no children, end description
}
// The end submenu. More than one submenu may end at once.
@@ -101,7 +123,6 @@ public class MenuBar extends AbstractComponent {
itr = iteratorStack.pop();
target.endTag("item");
}
-
}
target.endTag("items");
@@ -138,7 +159,7 @@ public class MenuBar extends AbstractComponent {
}// while
// If we got the clicked item, launch the command.
- if (found) {
+ if (found && tmpItem.isEnabled()) {
tmpItem.getCommand().menuSelected(tmpItem);
}
}// if
@@ -270,40 +291,46 @@ public class MenuBar extends AbstractComponent {
* Set the icon to be used if a sub-menu has children. Defaults to null;
*
* @param icon
+ * @deprecated (since 6.2, will be removed in 7.0) Icon is set in theme, no
+ * need to worry about the visual representation here.
*/
+ @Deprecated
public void setSubmenuIcon(Resource icon) {
submenuIcon = icon;
requestRepaint();
}
/**
- * Get the icon used for sub-menus. Returns null if no icon is set.
- *
- * @return
+ * @deprecated
+ * @see #setSubmenuIcon(Resource)
*/
+ @Deprecated
public Resource getSubmenuIcon() {
return submenuIcon;
}
/**
* Enable or disable collapsing top-level items. Top-level items will
- * collapse to if there is not enough room for them. Items that don't fit
- * will be placed under the "More" menu item.
+ * collapse together if there is not enough room for them. Items that don't
+ * fit will be placed under the "More" menu item.
*
* Collapsing is enabled by default.
*
* @param collapse
+ * @deprecated (since 6.2, will be removed in 7.0) Collapsing is always
+ * enabled if the MenuBar has a specified width.
*/
+ @Deprecated
public void setCollapse(boolean collapse) {
collapseItems = collapse;
requestRepaint();
}
/**
- * Collapsing is enabled by default.
- *
- * @return true if the top-level items will be collapsed
+ * @see #setCollapse(boolean)
+ * @deprecated
*/
+ @Deprecated
public boolean getCollapse() {
return collapseItems;
}
@@ -311,8 +338,9 @@ public class MenuBar extends AbstractComponent {
/**
* Set the item that is used when collapsing the top level menu. All
* "overflowing" items will be added below this. The item command will be
- * ignored. If set to null, the default item with the "More" text is be
- * used.
+ * ignored. If set to null, the default item with a downwards arrow is used.
+ *
+ * The item command (if specified) is ignored.
*
* @param item
*/
@@ -320,7 +348,7 @@ public class MenuBar extends AbstractComponent {
if (item != null) {
moreItem = item;
} else {
- moreItem = new MenuItem("More", null, null);
+ moreItem = new MenuItem("", null, null);
}
requestRepaint();
}
@@ -360,6 +388,9 @@ public class MenuBar extends AbstractComponent {
private List<MenuItem> itsChildren;
private Resource itsIcon;
private MenuItem itsParent;
+ private boolean enabled = true;
+ private boolean visible = true;
+ private boolean isSeparator = false;
/**
* Constructs a new menu item that can optionally have an icon and a
@@ -388,7 +419,27 @@ public class MenuBar extends AbstractComponent {
* @return True if this item has children
*/
public boolean hasChildren() {
- return itsChildren != null;
+ return !isSeparator() && itsChildren != null;
+ }
+
+ /**
+ * Adds a separator to this menu. A separator is a way to visually group
+ * items in a menu, to make it easier for users to find what they are
+ * looking for in the menu.
+ *
+ * @author Jouni Koivuviita / IT Mill Ltd.
+ * @since 6.2.0
+ */
+ public MenuBar.MenuItem addSeparator() {
+ MenuItem item = addItem("", null, null);
+ item.setSeparator(true);
+ return item;
+ }
+
+ public MenuBar.MenuItem addSeparatorBefore(MenuItem itemToAddBefore) {
+ MenuItem item = addItemBefore("", null, null, itemToAddBefore);
+ item.setSeparator(true);
+ return item;
}
/**
@@ -417,8 +468,12 @@ public class MenuBar extends AbstractComponent {
*/
public MenuBar.MenuItem addItem(String caption, Resource icon,
MenuBar.Command command) {
+ if (isSeparator()) {
+ throw new UnsupportedOperationException(
+ "Cannot add items to a separator");
+ }
if (caption == null) {
- throw new IllegalArgumentException("caption cannot be null");
+ throw new IllegalArgumentException("Caption cannot be null");
}
if (itsChildren == null) {
@@ -461,7 +516,6 @@ public class MenuBar extends AbstractComponent {
newItem = new MenuItem(caption, icon, command);
newItem.setParent(this);
itsChildren.add(index, newItem);
-
} else {
newItem = addItem(caption, icon, command);
}
@@ -524,7 +578,10 @@ public class MenuBar extends AbstractComponent {
* @return The number of child items
*/
public int getSize() {
- return itsChildren.size();
+ if (itsChildren != null) {
+ return itsChildren.size();
+ }
+ return -1;
}
/**
@@ -582,8 +639,8 @@ public class MenuBar extends AbstractComponent {
if (itsChildren.isEmpty()) {
itsChildren = null;
}
+ requestRepaint();
}
- requestRepaint();
}
/**
@@ -593,8 +650,8 @@ public class MenuBar extends AbstractComponent {
if (itsChildren != null) {
itsChildren.clear();
itsChildren = null;
+ requestRepaint();
}
- requestRepaint();
}
/**
@@ -607,6 +664,33 @@ public class MenuBar extends AbstractComponent {
itsParent = parent;
}
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ requestRepaint();
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setVisible(boolean visible) {
+ this.visible = visible;
+ requestRepaint();
+ }
+
+ public boolean isVisible() {
+ return visible;
+ }
+
+ private void setSeparator(boolean isSeparator) {
+ this.isSeparator = isSeparator;
+ requestRepaint();
+ }
+
+ public boolean isSeparator() {
+ return isSeparator;
+ }
+
}// class MenuItem
}// class MenuBar
diff --git a/src/com/vaadin/ui/TabSheet.java b/src/com/vaadin/ui/TabSheet.java
index ed81fdb655..b58e7be7bf 100644
--- a/src/com/vaadin/ui/TabSheet.java
+++ b/src/com/vaadin/ui/TabSheet.java
@@ -35,7 +35,7 @@ public class TabSheet extends AbstractComponentContainer implements
/**
* Linked list of component tabs.
*/
- private final LinkedList components = new LinkedList();
+ private final LinkedList<Component> components = new LinkedList<Component>();
/**
* Map containing information related to the tabs (caption, icon etc).
@@ -54,7 +54,9 @@ public class TabSheet extends AbstractComponentContainer implements
*/
private boolean tabsHidden;
- private LinkedList paintedTabs = new LinkedList();
+ private LinkedList<Component> paintedTabs = new LinkedList<Component>();
+
+ private CloseHandler closeHandler;
/**
* Constructs a new Tabsheet. Tabsheet is immediate by default.
@@ -64,6 +66,11 @@ public class TabSheet extends AbstractComponentContainer implements
// expand horizontally by default
setWidth(100, UNITS_PERCENTAGE);
setImmediate(true);
+ setCloseHandler(new CloseHandler() {
+ public void onTabClose(TabSheet tabsheet, Component c) {
+ tabsheet.removeComponent(c);
+ }
+ });
}
/**
@@ -72,7 +79,7 @@ public class TabSheet extends AbstractComponentContainer implements
*
* @return the Iterator of the components inside the container.
*/
- public Iterator getComponentIterator() {
+ public Iterator<Component> getComponentIterator() {
return java.util.Collections.unmodifiableList(components).iterator();
}
@@ -93,7 +100,7 @@ public class TabSheet extends AbstractComponentContainer implements
if (components.isEmpty()) {
selected = null;
} else {
- selected = (Component) components.getFirst();
+ selected = components.getFirst();
fireSelectedTabChange();
}
}
@@ -168,8 +175,9 @@ public class TabSheet extends AbstractComponentContainer implements
*/
@Override
public void moveComponentsFrom(ComponentContainer source) {
- for (final Iterator i = source.getComponentIterator(); i.hasNext();) {
- final Component c = (Component) i.next();
+ for (final Iterator<Component> i = source.getComponentIterator(); i
+ .hasNext();) {
+ final Component c = i.next();
String caption = null;
Resource icon = null;
if (TabSheet.class.isAssignableFrom(source.getClass())) {
@@ -199,8 +207,8 @@ public class TabSheet extends AbstractComponentContainer implements
target.startTag("tabs");
- for (final Iterator i = getComponentIterator(); i.hasNext();) {
- final Component component = (Component) i.next();
+ for (final Iterator<Component> i = getComponentIterator(); i.hasNext();) {
+ final Component component = i.next();
Tab tab = tabs.get(component);
/*
@@ -236,6 +244,10 @@ public class TabSheet extends AbstractComponentContainer implements
target.addAttribute("hidden", true);
}
+ if (tab.isClosable()) {
+ target.addAttribute("closable", true);
+ }
+
final Resource icon = tab.getIcon();
if (icon != null) {
target.addAttribute("icon", icon);
@@ -417,6 +429,13 @@ public class TabSheet extends AbstractComponentContainer implements
setSelectedTab((Component) keyMapper.get((String) variables
.get("selected")));
}
+ if (variables.containsKey("close")) {
+ final Component tab = (Component) keyMapper.get((String) variables
+ .get("close"));
+ if (tab != null) {
+ closeHandler.onTabClose(this, tab);
+ }
+ }
}
/* Documented in superclass */
@@ -453,8 +472,8 @@ public class TabSheet extends AbstractComponentContainer implements
int oldLocation = -1;
int newLocation = -1;
int location = 0;
- for (final Iterator i = components.iterator(); i.hasNext();) {
- final Component component = (Component) i.next();
+ for (final Iterator<Component> i = components.iterator(); i.hasNext();) {
+ final Component component = i.next();
if (component == oldComponent) {
oldLocation = location;
@@ -636,6 +655,23 @@ public class TabSheet extends AbstractComponentContainer implements
public void setVisible(boolean visible);
/**
+ * Returns the closability status for the tab.
+ *
+ * @return true if the tab is allowed to be closed by the end user,
+ * false for not allowing closing
+ */
+ public boolean isClosable();
+
+ /**
+ * Sets the closability status for the tab.
+ *
+ * @param visible
+ * true if the end user is allowed to close the tab, false
+ * for not allowing to close. Should default to false.
+ */
+ public void setClosable(boolean closable);
+
+ /**
* Returns the enabled status for the tab.
*
* @return true for enabled, false for disabled
@@ -710,6 +746,7 @@ public class TabSheet extends AbstractComponentContainer implements
private Resource icon = null;
private boolean enabled = true;
private boolean visible = true;
+ private boolean closable = false;
private String description = null;
private ErrorMessage componentError = null;
@@ -760,6 +797,19 @@ public class TabSheet extends AbstractComponentContainer implements
requestRepaint();
}
+ public boolean isClosable() {
+ return closable;
+ }
+
+ public void setClosable(boolean closable) {
+ this.closable = closable;
+ requestRepaint();
+ }
+
+ public void close() {
+
+ }
+
public String getDescription() {
return description;
}
@@ -777,6 +827,44 @@ public class TabSheet extends AbstractComponentContainer implements
this.componentError = componentError;
requestRepaint();
}
+ }
+
+ /**
+ * CloseHandler is used to process tab closing events. Default behavior is
+ * to remove the tab from the TabSheet.
+ *
+ * @author Jouni Koivuviita / IT Mill Ltd.
+ * @since 6.2.0
+ *
+ */
+ public interface CloseHandler {
+ /**
+ * Called when a user has pressed the close icon of a tab in the client
+ * side widget.
+ *
+ * @param tabsheet
+ * the TabSheet to which the tab belongs to
+ * @param tabContent
+ * the component that corresponds to the tab whose close
+ * button was clicked
+ */
+ void onTabClose(final TabSheet tabsheet, final Component tabContent);
+ }
+
+ /**
+ * Provide a custom {@link CloseHandler} for this TabSheet if you wish to
+ * perform some additional tasks when a user clicks on a tabs close button,
+ * e.g. show a confirmation dialogue before removing the tab.
+ *
+ * To remove the tab, if you provide your own close handler, you must call
+ * {@link #removeComponent(Component)} yourself.
+ *
+ * The default CloseHandler for TabSheet will only remove the tab.
+ *
+ * @param handler
+ */
+ public void setCloseHandler(CloseHandler handler) {
+ closeHandler = handler;
}
}
diff --git a/src/com/vaadin/ui/Upload.java b/src/com/vaadin/ui/Upload.java
index dfbbbfc103..e3512a4795 100644
--- a/src/com/vaadin/ui/Upload.java
+++ b/src/com/vaadin/ui/Upload.java
@@ -244,8 +244,6 @@ public class Upload extends AbstractComponent implements Component.Focusable {
target.addAttribute("buttoncaption", buttonCaption);
- target.addVariable(this, "fake", true);
-
target.addUploadStreamVariable(this, "stream");
}
diff --git a/src/com/vaadin/ui/Window.java b/src/com/vaadin/ui/Window.java
index dc1bf7e18f..d234f7aaac 100644
--- a/src/com/vaadin/ui/Window.java
+++ b/src/com/vaadin/ui/Window.java
@@ -8,6 +8,7 @@ import java.io.Serializable;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
@@ -119,6 +120,8 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
private Focusable pendingFocus;
+ private ArrayList<String> jsExecQueue = null;
+
/* ********************************************************************* */
/**
@@ -381,7 +384,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
if (getParent() != null) {
// this is subwindow
Window mainWindow = (Window) getParent();
- mainWindow.addParameterHandler(handler);
+ mainWindow.removeParameterHandler(handler);
} else {
if (handler == null || parameterHandlerList == null) {
return;
@@ -520,6 +523,16 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
// Contents of the window panel is painted
super.paintContent(target);
+ // Add executable javascripts if needed
+ if (jsExecQueue != null) {
+ for (String script : jsExecQueue) {
+ target.startTag("execJS");
+ target.addAttribute("script", script);
+ target.endTag("execJS");
+ }
+ jsExecQueue = null;
+ }
+
// Window position
target.addVariable(this, "positionx", getPositionX());
target.addVariable(this, "positiony", getPositionY());
@@ -1632,4 +1645,39 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
}
}
+ /**
+ * Executes JavaScript in this window.
+ *
+ * <p>
+ * This method allows one to inject javascript from the server to client. A
+ * client implementation is not required to implement this functionality,
+ * but currently all web-based clients do implement this.
+ * </p>
+ *
+ * <p>
+ * Executing javascript this way often leads to cross-browser compatibility
+ * issues and regressions that are hard to resolve. Use of this method
+ * should be avoided and instead it is recommended to create new widgets
+ * with GWT. For more info on creating own, reusable client-side widgets in
+ * Java, read the corresponding chapter in Book of Vaadin.
+ * </p>
+ *
+ * @param script
+ * JavaScript snippet that will be executed.
+ */
+ public void executeJavaScript(String script) {
+
+ if (getParent() != null) {
+ throw new UnsupportedOperationException(
+ "Only application level windows can execute javascript.");
+ }
+
+ if (jsExecQueue == null) {
+ jsExecQueue = new ArrayList<String>();
+ }
+
+ jsExecQueue.add(script);
+
+ requestRepaint();
+ }
}