From c2722bfeb2552158c9717110b35518a07e13ab85 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 27 Jan 2012 14:08:53 +0000 Subject: #8311 Converted CRLF to LF in all source files svn changeset:22797/svn branch:6.7 --- .../google/gwt/dom/client/VaadinDOMImplSafari.java | 52 +- src/com/vaadin/data/util/TextFileProperty.java | 282 +- .../data/util/sqlcontainer/CacheFlushNotifier.java | 184 +- .../vaadin/data/util/sqlcontainer/CacheMap.java | 60 +- .../vaadin/data/util/sqlcontainer/Reference.java | 112 +- src/com/vaadin/data/util/sqlcontainer/RowId.java | 162 +- .../connection/SimpleJDBCConnectionPool.java | 330 +- .../query/FreeformStatementDelegate.java | 114 +- .../query/generator/StatementHelper.java | 270 +- src/com/vaadin/event/FieldEvents.java | 500 +-- .../terminal/gwt/client/DateTimeService.java | 878 ++--- .../gwt/client/LocaleNotLoadedException.java | 26 +- .../vaadin/terminal/gwt/client/LocaleService.java | 296 +- .../terminal/gwt/client/VBrowserDetails.java | 610 ++-- .../vaadin/terminal/gwt/client/VSchedulerImpl.java | 64 +- .../terminal/gwt/client/ui/CalendarEntry.java | 254 +- .../terminal/gwt/client/ui/FocusableFlowPanel.java | 198 +- .../vaadin/terminal/gwt/client/ui/TreeImages.java | 58 +- .../terminal/gwt/client/ui/VCalendarPanel.java | 3579 ++++++++++---------- .../vaadin/terminal/gwt/client/ui/VDateField.java | 554 +-- .../terminal/gwt/client/ui/VDateFieldCalendar.java | 306 +- src/com/vaadin/terminal/gwt/client/ui/VForm.java | 662 ++-- .../terminal/gwt/client/ui/VLazyExecutor.java | 104 +- .../terminal/gwt/client/ui/VNotification.java | 834 ++--- .../terminal/gwt/client/ui/VOptionGroup.java | 470 +-- .../terminal/gwt/client/ui/VOptionGroupBase.java | 454 +-- .../terminal/gwt/client/ui/VOrderedLayout.java | 2 +- .../terminal/gwt/client/ui/VPasswordField.java | 42 +- .../terminal/gwt/client/ui/VPopupCalendar.java | 964 +++--- src/com/vaadin/terminal/gwt/client/ui/VSlider.java | 1202 +++---- .../terminal/gwt/client/ui/VTabsheetPanel.java | 428 +-- .../vaadin/terminal/gwt/client/ui/VTextArea.java | 158 +- .../terminal/gwt/client/ui/VTwinColSelect.java | 1290 +++---- src/com/vaadin/ui/ComboBox.java | 258 +- src/com/vaadin/ui/InlineDateField.java | 96 +- src/com/vaadin/ui/PopupDateField.java | 160 +- 36 files changed, 8011 insertions(+), 8002 deletions(-) (limited to 'src/com') diff --git a/src/com/google/gwt/dom/client/VaadinDOMImplSafari.java b/src/com/google/gwt/dom/client/VaadinDOMImplSafari.java index 3975bf73d8..6e9cc81f43 100644 --- a/src/com/google/gwt/dom/client/VaadinDOMImplSafari.java +++ b/src/com/google/gwt/dom/client/VaadinDOMImplSafari.java @@ -1,26 +1,26 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.google.gwt.dom.client; - -/** - * Overridden to workaround GWT issue #6194. Remove this when updating to a - * newer GWT that fixes the problem (2.3.0 possibly). Must be in this package as - * the whole DOMImpl hierarchy is package private and I really did not want to - * copy all the parent classes into this one... - */ -class VaadinDOMImplSafari extends DOMImplSafari { - @Override - public int getAbsoluteLeft(Element elem) { - // Chrome returns a float in certain cases (at least when zoom != 100%). - // The |0 ensures it is converted to an int. - return super.getAbsoluteLeft(elem) | 0; - } - - @Override - public int getAbsoluteTop(Element elem) { - // Chrome returns a float in certain cases (at least when zoom != 100%). - // The |0 ensures it is converted to an int. - return super.getAbsoluteTop(elem) | 0; - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.google.gwt.dom.client; + +/** + * Overridden to workaround GWT issue #6194. Remove this when updating to a + * newer GWT that fixes the problem (2.3.0 possibly). Must be in this package as + * the whole DOMImpl hierarchy is package private and I really did not want to + * copy all the parent classes into this one... + */ +class VaadinDOMImplSafari extends DOMImplSafari { + @Override + public int getAbsoluteLeft(Element elem) { + // Chrome returns a float in certain cases (at least when zoom != 100%). + // The |0 ensures it is converted to an int. + return super.getAbsoluteLeft(elem) | 0; + } + + @Override + public int getAbsoluteTop(Element elem) { + // Chrome returns a float in certain cases (at least when zoom != 100%). + // The |0 ensures it is converted to an int. + return super.getAbsoluteTop(elem) | 0; + } +} diff --git a/src/com/vaadin/data/util/TextFileProperty.java b/src/com/vaadin/data/util/TextFileProperty.java index 2ad1f593af..cfa8d4fabf 100644 --- a/src/com/vaadin/data/util/TextFileProperty.java +++ b/src/com/vaadin/data/util/TextFileProperty.java @@ -1,141 +1,141 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.nio.charset.Charset; - -/** - * Property implementation for wrapping a text file. - * - * Supports reading and writing of a File from/to String. - * - * {@link ValueChangeListener}s are supported, but only fire when - * setValue(Object) is explicitly called. {@link ReadOnlyStatusChangeListener}s - * are supported but only fire when setReadOnly(boolean) is explicitly called. - * - */ -@SuppressWarnings("serial") -public class TextFileProperty extends AbstractProperty { - - private File file; - private Charset charset = null; - - /** - * Wrap given file with property interface. - * - * Setting the file to null works, but getValue() will return null. - * - * @param file - * File to be wrapped. - */ - public TextFileProperty(File file) { - this.file = file; - } - - /** - * Wrap the given file with the property interface and specify character - * set. - * - * Setting the file to null works, but getValue() will return null. - * - * @param file - * File to be wrapped. - * @param charset - * Charset to be used for reading and writing the file. - */ - public TextFileProperty(File file, Charset charset) { - this.file = file; - this.charset = charset; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#getType() - */ - public Class getType() { - return String.class; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#getValue() - */ - public Object getValue() { - if (file == null) { - return null; - } - try { - FileInputStream fis = new FileInputStream(file); - InputStreamReader isr = charset == null ? new InputStreamReader(fis) - : new InputStreamReader(fis, charset); - BufferedReader r = new BufferedReader(isr); - StringBuilder b = new StringBuilder(); - char buf[] = new char[8 * 1024]; - int len; - while ((len = r.read(buf)) != -1) { - b.append(buf, 0, len); - } - r.close(); - isr.close(); - fis.close(); - return b.toString(); - } catch (FileNotFoundException e) { - return null; - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#isReadOnly() - */ - @Override - public boolean isReadOnly() { - return file == null || super.isReadOnly() || !file.canWrite(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#setValue(java.lang.Object) - */ - public void setValue(Object newValue) throws ReadOnlyException { - if (isReadOnly()) { - throw new ReadOnlyException(); - } - if (file == null) { - return; - } - - try { - FileOutputStream fos = new FileOutputStream(file); - OutputStreamWriter osw = charset == null ? new OutputStreamWriter( - fos) : new OutputStreamWriter(fos, charset); - BufferedWriter w = new BufferedWriter(osw); - w.append(newValue.toString()); - w.flush(); - w.close(); - osw.close(); - fos.close(); - fireValueChange(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.data.util; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; + +/** + * Property implementation for wrapping a text file. + * + * Supports reading and writing of a File from/to String. + * + * {@link ValueChangeListener}s are supported, but only fire when + * setValue(Object) is explicitly called. {@link ReadOnlyStatusChangeListener}s + * are supported but only fire when setReadOnly(boolean) is explicitly called. + * + */ +@SuppressWarnings("serial") +public class TextFileProperty extends AbstractProperty { + + private File file; + private Charset charset = null; + + /** + * Wrap given file with property interface. + * + * Setting the file to null works, but getValue() will return null. + * + * @param file + * File to be wrapped. + */ + public TextFileProperty(File file) { + this.file = file; + } + + /** + * Wrap the given file with the property interface and specify character + * set. + * + * Setting the file to null works, but getValue() will return null. + * + * @param file + * File to be wrapped. + * @param charset + * Charset to be used for reading and writing the file. + */ + public TextFileProperty(File file, Charset charset) { + this.file = file; + this.charset = charset; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.Property#getType() + */ + public Class getType() { + return String.class; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.Property#getValue() + */ + public Object getValue() { + if (file == null) { + return null; + } + try { + FileInputStream fis = new FileInputStream(file); + InputStreamReader isr = charset == null ? new InputStreamReader(fis) + : new InputStreamReader(fis, charset); + BufferedReader r = new BufferedReader(isr); + StringBuilder b = new StringBuilder(); + char buf[] = new char[8 * 1024]; + int len; + while ((len = r.read(buf)) != -1) { + b.append(buf, 0, len); + } + r.close(); + isr.close(); + fis.close(); + return b.toString(); + } catch (FileNotFoundException e) { + return null; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.Property#isReadOnly() + */ + @Override + public boolean isReadOnly() { + return file == null || super.isReadOnly() || !file.canWrite(); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.Property#setValue(java.lang.Object) + */ + public void setValue(Object newValue) throws ReadOnlyException { + if (isReadOnly()) { + throw new ReadOnlyException(); + } + if (file == null) { + return; + } + + try { + FileOutputStream fos = new FileOutputStream(file); + OutputStreamWriter osw = charset == null ? new OutputStreamWriter( + fos) : new OutputStreamWriter(fos, charset); + BufferedWriter w = new BufferedWriter(osw); + w.append(newValue.toString()); + w.flush(); + w.close(); + osw.close(); + fos.close(); + fireValueChange(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/com/vaadin/data/util/sqlcontainer/CacheFlushNotifier.java b/src/com/vaadin/data/util/sqlcontainer/CacheFlushNotifier.java index ac6efaa49b..788966048d 100644 --- a/src/com/vaadin/data/util/sqlcontainer/CacheFlushNotifier.java +++ b/src/com/vaadin/data/util/sqlcontainer/CacheFlushNotifier.java @@ -1,92 +1,92 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import java.io.Serializable; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; - -import com.vaadin.data.util.sqlcontainer.query.FreeformQuery; -import com.vaadin.data.util.sqlcontainer.query.QueryDelegate; -import com.vaadin.data.util.sqlcontainer.query.TableQuery; - -/** - * CacheFlushNotifier is a simple static notification mechanism to inform other - * SQLContainers that the contents of their caches may have become stale. - */ -class CacheFlushNotifier implements Serializable { - /* - * SQLContainer instance reference list and dead reference queue. Used for - * the cache flush notification feature. - */ - private static List> allInstances = new ArrayList>(); - private static ReferenceQueue deadInstances = new ReferenceQueue(); - - /** - * Adds the given SQLContainer to the cache flush notification receiver list - * - * @param c - * Container to add - */ - public static void addInstance(SQLContainer c) { - removeDeadReferences(); - if (c != null) { - allInstances.add(new WeakReference(c, deadInstances)); - } - } - - /** - * Removes dead references from instance list - */ - private static void removeDeadReferences() { - java.lang.ref.Reference dead = deadInstances - .poll(); - while (dead != null) { - allInstances.remove(dead); - dead = deadInstances.poll(); - } - } - - /** - * Iterates through the instances and notifies containers which are - * connected to the same table or are using the same query string. - * - * @param c - * SQLContainer that issued the cache flush notification - */ - public static void notifyOfCacheFlush(SQLContainer c) { - removeDeadReferences(); - for (WeakReference wr : allInstances) { - if (wr.get() != null) { - SQLContainer wrc = wr.get(); - if (wrc == null) { - continue; - } - /* - * If the reference points to the container sending the - * notification, do nothing. - */ - if (wrc.equals(c)) { - continue; - } - /* Compare QueryDelegate types and tableName/queryString */ - QueryDelegate wrQd = wrc.getQueryDelegate(); - QueryDelegate qd = c.getQueryDelegate(); - if (wrQd instanceof TableQuery - && qd instanceof TableQuery - && ((TableQuery) wrQd).getTableName().equals( - ((TableQuery) qd).getTableName())) { - wrc.refresh(); - } else if (wrQd instanceof FreeformQuery - && qd instanceof FreeformQuery - && ((FreeformQuery) wrQd).getQueryString().equals( - ((FreeformQuery) qd).getQueryString())) { - wrc.refresh(); - } - } - } - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.util.sqlcontainer; + +import java.io.Serializable; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; + +import com.vaadin.data.util.sqlcontainer.query.FreeformQuery; +import com.vaadin.data.util.sqlcontainer.query.QueryDelegate; +import com.vaadin.data.util.sqlcontainer.query.TableQuery; + +/** + * CacheFlushNotifier is a simple static notification mechanism to inform other + * SQLContainers that the contents of their caches may have become stale. + */ +class CacheFlushNotifier implements Serializable { + /* + * SQLContainer instance reference list and dead reference queue. Used for + * the cache flush notification feature. + */ + private static List> allInstances = new ArrayList>(); + private static ReferenceQueue deadInstances = new ReferenceQueue(); + + /** + * Adds the given SQLContainer to the cache flush notification receiver list + * + * @param c + * Container to add + */ + public static void addInstance(SQLContainer c) { + removeDeadReferences(); + if (c != null) { + allInstances.add(new WeakReference(c, deadInstances)); + } + } + + /** + * Removes dead references from instance list + */ + private static void removeDeadReferences() { + java.lang.ref.Reference dead = deadInstances + .poll(); + while (dead != null) { + allInstances.remove(dead); + dead = deadInstances.poll(); + } + } + + /** + * Iterates through the instances and notifies containers which are + * connected to the same table or are using the same query string. + * + * @param c + * SQLContainer that issued the cache flush notification + */ + public static void notifyOfCacheFlush(SQLContainer c) { + removeDeadReferences(); + for (WeakReference wr : allInstances) { + if (wr.get() != null) { + SQLContainer wrc = wr.get(); + if (wrc == null) { + continue; + } + /* + * If the reference points to the container sending the + * notification, do nothing. + */ + if (wrc.equals(c)) { + continue; + } + /* Compare QueryDelegate types and tableName/queryString */ + QueryDelegate wrQd = wrc.getQueryDelegate(); + QueryDelegate qd = c.getQueryDelegate(); + if (wrQd instanceof TableQuery + && qd instanceof TableQuery + && ((TableQuery) wrQd).getTableName().equals( + ((TableQuery) qd).getTableName())) { + wrc.refresh(); + } else if (wrQd instanceof FreeformQuery + && qd instanceof FreeformQuery + && ((FreeformQuery) wrQd).getQueryString().equals( + ((FreeformQuery) qd).getQueryString())) { + wrc.refresh(); + } + } + } + } +} diff --git a/src/com/vaadin/data/util/sqlcontainer/CacheMap.java b/src/com/vaadin/data/util/sqlcontainer/CacheMap.java index 44921dd12d..839fceb3c2 100644 --- a/src/com/vaadin/data/util/sqlcontainer/CacheMap.java +++ b/src/com/vaadin/data/util/sqlcontainer/CacheMap.java @@ -1,31 +1,31 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * CacheMap extends LinkedHashMap, adding the possibility to adjust maximum - * number of items. In SQLContainer this is used for RowItem -cache. Cache size - * will be two times the page length parameter of the container. - */ -class CacheMap extends LinkedHashMap { - private static final long serialVersionUID = 679999766473555231L; - private int cacheLimit = SQLContainer.CACHE_RATIO - * SQLContainer.DEFAULT_PAGE_LENGTH; - - @Override - protected boolean removeEldestEntry(Map.Entry eldest) { - return size() > cacheLimit; - } - - void setCacheLimit(int limit) { - cacheLimit = limit > 0 ? limit : SQLContainer.DEFAULT_PAGE_LENGTH; - } - - int getCacheLimit() { - return cacheLimit; - } +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.util.sqlcontainer; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * CacheMap extends LinkedHashMap, adding the possibility to adjust maximum + * number of items. In SQLContainer this is used for RowItem -cache. Cache size + * will be two times the page length parameter of the container. + */ +class CacheMap extends LinkedHashMap { + private static final long serialVersionUID = 679999766473555231L; + private int cacheLimit = SQLContainer.CACHE_RATIO + * SQLContainer.DEFAULT_PAGE_LENGTH; + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > cacheLimit; + } + + void setCacheLimit(int limit) { + cacheLimit = limit > 0 ? limit : SQLContainer.DEFAULT_PAGE_LENGTH; + } + + int getCacheLimit() { + return cacheLimit; + } } \ No newline at end of file diff --git a/src/com/vaadin/data/util/sqlcontainer/Reference.java b/src/com/vaadin/data/util/sqlcontainer/Reference.java index 6e863fa040..dea1aa87c0 100644 --- a/src/com/vaadin/data/util/sqlcontainer/Reference.java +++ b/src/com/vaadin/data/util/sqlcontainer/Reference.java @@ -1,56 +1,56 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import java.io.Serializable; - -/** - * The reference class represents a simple [usually foreign key] reference to - * another SQLContainer. Actual foreign key reference in the database is not - * required, but it is recommended to make sure that certain constraints are - * followed. - */ -@SuppressWarnings("serial") -class Reference implements Serializable { - - /** - * The SQLContainer that this reference points to. - */ - private SQLContainer referencedContainer; - - /** - * The column ID/name in the referencing SQLContainer that contains the key - * used for the reference. - */ - private String referencingColumn; - - /** - * The column ID/name in the referenced SQLContainer that contains the key - * used for the reference. - */ - private String referencedColumn; - - /** - * Constructs a new reference to be used within the SQLContainer to - * reference another SQLContainer. - */ - Reference(SQLContainer referencedContainer, String referencingColumn, - String referencedColumn) { - this.referencedContainer = referencedContainer; - this.referencingColumn = referencingColumn; - this.referencedColumn = referencedColumn; - } - - SQLContainer getReferencedContainer() { - return referencedContainer; - } - - String getReferencingColumn() { - return referencingColumn; - } - - String getReferencedColumn() { - return referencedColumn; - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.util.sqlcontainer; + +import java.io.Serializable; + +/** + * The reference class represents a simple [usually foreign key] reference to + * another SQLContainer. Actual foreign key reference in the database is not + * required, but it is recommended to make sure that certain constraints are + * followed. + */ +@SuppressWarnings("serial") +class Reference implements Serializable { + + /** + * The SQLContainer that this reference points to. + */ + private SQLContainer referencedContainer; + + /** + * The column ID/name in the referencing SQLContainer that contains the key + * used for the reference. + */ + private String referencingColumn; + + /** + * The column ID/name in the referenced SQLContainer that contains the key + * used for the reference. + */ + private String referencedColumn; + + /** + * Constructs a new reference to be used within the SQLContainer to + * reference another SQLContainer. + */ + Reference(SQLContainer referencedContainer, String referencingColumn, + String referencedColumn) { + this.referencedContainer = referencedContainer; + this.referencingColumn = referencingColumn; + this.referencedColumn = referencedColumn; + } + + SQLContainer getReferencedContainer() { + return referencedContainer; + } + + String getReferencingColumn() { + return referencingColumn; + } + + String getReferencedColumn() { + return referencedColumn; + } +} diff --git a/src/com/vaadin/data/util/sqlcontainer/RowId.java b/src/com/vaadin/data/util/sqlcontainer/RowId.java index ed01b72e06..925325134a 100644 --- a/src/com/vaadin/data/util/sqlcontainer/RowId.java +++ b/src/com/vaadin/data/util/sqlcontainer/RowId.java @@ -1,81 +1,81 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import java.io.Serializable; - -/** - * RowId represents identifiers of a single database result set row. - * - * The data structure of a RowId is an Object array which contains the values of - * the primary key columns of the identified row. This allows easy equals() - * -comparison of RowItems. - */ -public class RowId implements Serializable { - private static final long serialVersionUID = -3161778404698901258L; - protected Object[] id; - - /** - * Prevent instantiation without required parameters. - */ - protected RowId() { - } - - public RowId(Object[] id) { - if (id == null) { - throw new IllegalArgumentException("id parameter must not be null!"); - } - this.id = id; - } - - public Object[] getId() { - return id; - } - - @Override - public int hashCode() { - int result = 31; - if (id != null) { - for (Object o : id) { - if (o != null) { - result += o.hashCode(); - } - } - } - return result; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof RowId)) { - return false; - } - Object[] compId = ((RowId) obj).getId(); - if (id == null && compId == null) { - return true; - } - if (id.length != compId.length) { - return false; - } - for (int i = 0; i < id.length; i++) { - if ((id[i] == null && compId[i] != null) - || (id[i] != null && !id[i].equals(compId[i]))) { - return false; - } - } - return true; - } - - @Override - public String toString() { - StringBuffer s = new StringBuffer(); - for (int i = 0; i < id.length; i++) { - s.append(id[i]); - if (i < id.length - 1) { - s.append("/"); - } - } - return s.toString(); - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.util.sqlcontainer; + +import java.io.Serializable; + +/** + * RowId represents identifiers of a single database result set row. + * + * The data structure of a RowId is an Object array which contains the values of + * the primary key columns of the identified row. This allows easy equals() + * -comparison of RowItems. + */ +public class RowId implements Serializable { + private static final long serialVersionUID = -3161778404698901258L; + protected Object[] id; + + /** + * Prevent instantiation without required parameters. + */ + protected RowId() { + } + + public RowId(Object[] id) { + if (id == null) { + throw new IllegalArgumentException("id parameter must not be null!"); + } + this.id = id; + } + + public Object[] getId() { + return id; + } + + @Override + public int hashCode() { + int result = 31; + if (id != null) { + for (Object o : id) { + if (o != null) { + result += o.hashCode(); + } + } + } + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || !(obj instanceof RowId)) { + return false; + } + Object[] compId = ((RowId) obj).getId(); + if (id == null && compId == null) { + return true; + } + if (id.length != compId.length) { + return false; + } + for (int i = 0; i < id.length; i++) { + if ((id[i] == null && compId[i] != null) + || (id[i] != null && !id[i].equals(compId[i]))) { + return false; + } + } + return true; + } + + @Override + public String toString() { + StringBuffer s = new StringBuffer(); + for (int i = 0; i < id.length; i++) { + s.append(id[i]); + if (i < id.length - 1) { + s.append("/"); + } + } + return s.toString(); + } +} diff --git a/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPool.java b/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPool.java index c1a7c61eab..2a1068e786 100644 --- a/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPool.java +++ b/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPool.java @@ -1,165 +1,165 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.connection; - -import java.io.IOException; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.HashSet; -import java.util.Set; - -/** - * Simple implementation of the JDBCConnectionPool interface. Handles loading - * the JDBC driver, setting up the connections and ensuring they are still - * usable upon release. - */ -@SuppressWarnings("serial") -public class SimpleJDBCConnectionPool implements JDBCConnectionPool { - - private int initialConnections = 5; - private int maxConnections = 20; - - private String driverName; - private String connectionUri; - private String userName; - private String password; - - private transient Set availableConnections; - private transient Set reservedConnections; - - private boolean initialized; - - public SimpleJDBCConnectionPool(String driverName, String connectionUri, - String userName, String password) throws SQLException { - if (driverName == null) { - throw new IllegalArgumentException( - "JDBC driver class name must be given."); - } - if (connectionUri == null) { - throw new IllegalArgumentException( - "Database connection URI must be given."); - } - if (userName == null) { - throw new IllegalArgumentException( - "Database username must be given."); - } - if (password == null) { - throw new IllegalArgumentException( - "Database password must be given."); - } - this.driverName = driverName; - this.connectionUri = connectionUri; - this.userName = userName; - this.password = password; - - /* Initialize JDBC driver */ - try { - Class.forName(driverName).newInstance(); - } catch (Exception ex) { - throw new RuntimeException("Specified JDBC Driver: " + driverName - + " - initialization failed.", ex); - } - } - - public SimpleJDBCConnectionPool(String driverName, String connectionUri, - String userName, String password, int initialConnections, - int maxConnections) throws SQLException { - this(driverName, connectionUri, userName, password); - this.initialConnections = initialConnections; - this.maxConnections = maxConnections; - } - - private void initializeConnections() throws SQLException { - availableConnections = new HashSet(initialConnections); - reservedConnections = new HashSet(initialConnections); - for (int i = 0; i < initialConnections; i++) { - availableConnections.add(createConnection()); - } - initialized = true; - } - - public synchronized Connection reserveConnection() throws SQLException { - if (!initialized) { - initializeConnections(); - } - if (availableConnections.isEmpty()) { - if (reservedConnections.size() < maxConnections) { - availableConnections.add(createConnection()); - } else { - throw new SQLException("Connection limit has been reached."); - } - } - - Connection c = availableConnections.iterator().next(); - availableConnections.remove(c); - reservedConnections.add(c); - - return c; - } - - public synchronized void releaseConnection(Connection conn) { - if (conn == null || !initialized) { - return; - } - /* Try to roll back if necessary */ - try { - if (!conn.getAutoCommit()) { - conn.rollback(); - } - } catch (SQLException e) { - /* Roll back failed, close and discard connection */ - try { - conn.close(); - } catch (SQLException e1) { - /* Nothing needs to be done */ - } - reservedConnections.remove(conn); - return; - } - reservedConnections.remove(conn); - availableConnections.add(conn); - } - - private Connection createConnection() throws SQLException { - Connection c = DriverManager.getConnection(connectionUri, userName, - password); - c.setAutoCommit(false); - if (driverName.toLowerCase().contains("mysql")) { - try { - Statement s = c.createStatement(); - s.execute("SET SESSION sql_mode = 'ANSI'"); - s.close(); - } catch (Exception e) { - // Failed to set ansi mode; continue - } - } - return c; - } - - public void destroy() { - for (Connection c : availableConnections) { - try { - c.close(); - } catch (SQLException e) { - // No need to do anything - } - } - for (Connection c : reservedConnections) { - try { - c.close(); - } catch (SQLException e) { - // No need to do anything - } - } - - } - - private void writeObject(java.io.ObjectOutputStream out) throws IOException { - initialized = false; - out.defaultWriteObject(); - } - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.util.sqlcontainer.connection; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashSet; +import java.util.Set; + +/** + * Simple implementation of the JDBCConnectionPool interface. Handles loading + * the JDBC driver, setting up the connections and ensuring they are still + * usable upon release. + */ +@SuppressWarnings("serial") +public class SimpleJDBCConnectionPool implements JDBCConnectionPool { + + private int initialConnections = 5; + private int maxConnections = 20; + + private String driverName; + private String connectionUri; + private String userName; + private String password; + + private transient Set availableConnections; + private transient Set reservedConnections; + + private boolean initialized; + + public SimpleJDBCConnectionPool(String driverName, String connectionUri, + String userName, String password) throws SQLException { + if (driverName == null) { + throw new IllegalArgumentException( + "JDBC driver class name must be given."); + } + if (connectionUri == null) { + throw new IllegalArgumentException( + "Database connection URI must be given."); + } + if (userName == null) { + throw new IllegalArgumentException( + "Database username must be given."); + } + if (password == null) { + throw new IllegalArgumentException( + "Database password must be given."); + } + this.driverName = driverName; + this.connectionUri = connectionUri; + this.userName = userName; + this.password = password; + + /* Initialize JDBC driver */ + try { + Class.forName(driverName).newInstance(); + } catch (Exception ex) { + throw new RuntimeException("Specified JDBC Driver: " + driverName + + " - initialization failed.", ex); + } + } + + public SimpleJDBCConnectionPool(String driverName, String connectionUri, + String userName, String password, int initialConnections, + int maxConnections) throws SQLException { + this(driverName, connectionUri, userName, password); + this.initialConnections = initialConnections; + this.maxConnections = maxConnections; + } + + private void initializeConnections() throws SQLException { + availableConnections = new HashSet(initialConnections); + reservedConnections = new HashSet(initialConnections); + for (int i = 0; i < initialConnections; i++) { + availableConnections.add(createConnection()); + } + initialized = true; + } + + public synchronized Connection reserveConnection() throws SQLException { + if (!initialized) { + initializeConnections(); + } + if (availableConnections.isEmpty()) { + if (reservedConnections.size() < maxConnections) { + availableConnections.add(createConnection()); + } else { + throw new SQLException("Connection limit has been reached."); + } + } + + Connection c = availableConnections.iterator().next(); + availableConnections.remove(c); + reservedConnections.add(c); + + return c; + } + + public synchronized void releaseConnection(Connection conn) { + if (conn == null || !initialized) { + return; + } + /* Try to roll back if necessary */ + try { + if (!conn.getAutoCommit()) { + conn.rollback(); + } + } catch (SQLException e) { + /* Roll back failed, close and discard connection */ + try { + conn.close(); + } catch (SQLException e1) { + /* Nothing needs to be done */ + } + reservedConnections.remove(conn); + return; + } + reservedConnections.remove(conn); + availableConnections.add(conn); + } + + private Connection createConnection() throws SQLException { + Connection c = DriverManager.getConnection(connectionUri, userName, + password); + c.setAutoCommit(false); + if (driverName.toLowerCase().contains("mysql")) { + try { + Statement s = c.createStatement(); + s.execute("SET SESSION sql_mode = 'ANSI'"); + s.close(); + } catch (Exception e) { + // Failed to set ansi mode; continue + } + } + return c; + } + + public void destroy() { + for (Connection c : availableConnections) { + try { + c.close(); + } catch (SQLException e) { + // No need to do anything + } + } + for (Connection c : reservedConnections) { + try { + c.close(); + } catch (SQLException e) { + // No need to do anything + } + } + + } + + private void writeObject(java.io.ObjectOutputStream out) throws IOException { + initialized = false; + out.defaultWriteObject(); + } + +} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/FreeformStatementDelegate.java b/src/com/vaadin/data/util/sqlcontainer/query/FreeformStatementDelegate.java index 2ea151c578..95521c5019 100644 --- a/src/com/vaadin/data/util/sqlcontainer/query/FreeformStatementDelegate.java +++ b/src/com/vaadin/data/util/sqlcontainer/query/FreeformStatementDelegate.java @@ -1,57 +1,57 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query; - -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -/** - * FreeformStatementDelegate is an extension to FreeformQueryDelegate that - * provides definitions for methods that produce StatementHelper objects instead - * of basic query strings. This allows the FreeformQuery query delegate to use - * PreparedStatements instead of regular Statement when accessing the database. - * - * Due to the injection protection and other benefits of prepared statements, it - * is advisable to implement this interface instead of the FreeformQueryDelegate - * whenever possible. - */ -public interface FreeformStatementDelegate extends FreeformQueryDelegate { - /** - * Should return a new instance of StatementHelper that contains the query - * string and parameter values required to create a PreparedStatement. This - * method is responsible for gluing together the select query from the - * filters and the order by conditions if these are supported. - * - * @param offset - * the first record (row) to fetch. - * @param pagelength - * the number of records (rows) to fetch. 0 means all records - * starting from offset. - */ - public StatementHelper getQueryStatement(int offset, int limit) - throws UnsupportedOperationException; - - /** - * Should return a new instance of StatementHelper that contains the query - * string and parameter values required to create a PreparedStatement that - * will fetch the row count from the DB. Row count should be fetched using - * filters that are currently set to the QueryDelegate. - */ - public StatementHelper getCountStatement() - throws UnsupportedOperationException; - - /** - * Should return a new instance of StatementHelper that contains the query - * string and parameter values required to create a PreparedStatement used - * by the FreeformQuery.containsRowWithKeys() method. This is useful for - * cases when the default logic in said method is not enough to support more - * complex free form queries. - * - * @param keys - * the values of the primary keys - * @throws UnsupportedOperationException - * to use the default logic in FreeformQuery - */ - public StatementHelper getContainsRowQueryStatement(Object... keys) - throws UnsupportedOperationException; -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.util.sqlcontainer.query; + +import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; + +/** + * FreeformStatementDelegate is an extension to FreeformQueryDelegate that + * provides definitions for methods that produce StatementHelper objects instead + * of basic query strings. This allows the FreeformQuery query delegate to use + * PreparedStatements instead of regular Statement when accessing the database. + * + * Due to the injection protection and other benefits of prepared statements, it + * is advisable to implement this interface instead of the FreeformQueryDelegate + * whenever possible. + */ +public interface FreeformStatementDelegate extends FreeformQueryDelegate { + /** + * Should return a new instance of StatementHelper that contains the query + * string and parameter values required to create a PreparedStatement. This + * method is responsible for gluing together the select query from the + * filters and the order by conditions if these are supported. + * + * @param offset + * the first record (row) to fetch. + * @param pagelength + * the number of records (rows) to fetch. 0 means all records + * starting from offset. + */ + public StatementHelper getQueryStatement(int offset, int limit) + throws UnsupportedOperationException; + + /** + * Should return a new instance of StatementHelper that contains the query + * string and parameter values required to create a PreparedStatement that + * will fetch the row count from the DB. Row count should be fetched using + * filters that are currently set to the QueryDelegate. + */ + public StatementHelper getCountStatement() + throws UnsupportedOperationException; + + /** + * Should return a new instance of StatementHelper that contains the query + * string and parameter values required to create a PreparedStatement used + * by the FreeformQuery.containsRowWithKeys() method. This is useful for + * cases when the default logic in said method is not enough to support more + * complex free form queries. + * + * @param keys + * the values of the primary keys + * @throws UnsupportedOperationException + * to use the default logic in FreeformQuery + */ + public StatementHelper getContainsRowQueryStatement(Object... keys) + throws UnsupportedOperationException; +} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/StatementHelper.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/StatementHelper.java index 888f1ec501..3fd92e920d 100644 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/StatementHelper.java +++ b/src/com/vaadin/data/util/sqlcontainer/query/generator/StatementHelper.java @@ -1,135 +1,135 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator; - -import java.io.Serializable; -import java.math.BigDecimal; -import java.sql.Date; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Time; -import java.sql.Timestamp; -import java.sql.Types; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * StatementHelper is a simple helper class that assists TableQuery and the - * query generators in filling a PreparedStatement. The actual statement is - * generated by the query generator methods, but the resulting statement and all - * the parameter values are stored in an instance of StatementHelper. - * - * This class will also fill the values with correct setters into the - * PreparedStatement on request. - */ -public class StatementHelper implements Serializable { - - private String queryString; - - private List parameters = new ArrayList(); - private Map> dataTypes = new HashMap>(); - - public StatementHelper() { - } - - public void setQueryString(String queryString) { - this.queryString = queryString; - } - - public String getQueryString() { - return queryString; - } - - public void addParameterValue(Object parameter) { - if (parameter != null) { - parameters.add(parameter); - dataTypes.put(parameters.size() - 1, parameter.getClass()); - } - } - - public void addParameterValue(Object parameter, Class type) { - parameters.add(parameter); - dataTypes.put(parameters.size() - 1, type); - } - - public void setParameterValuesToStatement(PreparedStatement pstmt) - throws SQLException { - for (int i = 0; i < parameters.size(); i++) { - if (parameters.get(i) == null) { - handleNullValue(i, pstmt); - } else { - pstmt.setObject(i + 1, parameters.get(i)); - } - } - - /* - * The following list contains the data types supported by - * PreparedStatement but not supported by SQLContainer: - * - * [The list is provided as PreparedStatement method signatures] - * - * setNCharacterStream(int parameterIndex, Reader value) - * - * setNClob(int parameterIndex, NClob value) - * - * setNString(int parameterIndex, String value) - * - * setRef(int parameterIndex, Ref x) - * - * setRowId(int parameterIndex, RowId x) - * - * setSQLXML(int parameterIndex, SQLXML xmlObject) - * - * setBytes(int parameterIndex, byte[] x) - * - * setCharacterStream(int parameterIndex, Reader reader) - * - * setClob(int parameterIndex, Clob x) - * - * setURL(int parameterIndex, URL x) - * - * setArray(int parameterIndex, Array x) - * - * setAsciiStream(int parameterIndex, InputStream x) - * - * setBinaryStream(int parameterIndex, InputStream x) - * - * setBlob(int parameterIndex, Blob x) - */ - } - - private void handleNullValue(int i, PreparedStatement pstmt) - throws SQLException { - if (BigDecimal.class.equals(dataTypes.get(i))) { - pstmt.setBigDecimal(i + 1, null); - } else if (Boolean.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.BOOLEAN); - } else if (Byte.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.SMALLINT); - } else if (Date.class.equals(dataTypes.get(i))) { - pstmt.setDate(i + 1, null); - } else if (Double.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.DOUBLE); - } else if (Float.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.FLOAT); - } else if (Integer.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.INTEGER); - } else if (Long.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.BIGINT); - } else if (Short.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.SMALLINT); - } else if (String.class.equals(dataTypes.get(i))) { - pstmt.setString(i + 1, null); - } else if (Time.class.equals(dataTypes.get(i))) { - pstmt.setTime(i + 1, null); - } else if (Timestamp.class.equals(dataTypes.get(i))) { - pstmt.setTimestamp(i + 1, null); - } else { - throw new SQLException("Data type not supported by SQLContainer: " - + parameters.get(i).getClass().toString()); - } - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.util.sqlcontainer.query.generator; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.sql.Date; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Time; +import java.sql.Timestamp; +import java.sql.Types; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * StatementHelper is a simple helper class that assists TableQuery and the + * query generators in filling a PreparedStatement. The actual statement is + * generated by the query generator methods, but the resulting statement and all + * the parameter values are stored in an instance of StatementHelper. + * + * This class will also fill the values with correct setters into the + * PreparedStatement on request. + */ +public class StatementHelper implements Serializable { + + private String queryString; + + private List parameters = new ArrayList(); + private Map> dataTypes = new HashMap>(); + + public StatementHelper() { + } + + public void setQueryString(String queryString) { + this.queryString = queryString; + } + + public String getQueryString() { + return queryString; + } + + public void addParameterValue(Object parameter) { + if (parameter != null) { + parameters.add(parameter); + dataTypes.put(parameters.size() - 1, parameter.getClass()); + } + } + + public void addParameterValue(Object parameter, Class type) { + parameters.add(parameter); + dataTypes.put(parameters.size() - 1, type); + } + + public void setParameterValuesToStatement(PreparedStatement pstmt) + throws SQLException { + for (int i = 0; i < parameters.size(); i++) { + if (parameters.get(i) == null) { + handleNullValue(i, pstmt); + } else { + pstmt.setObject(i + 1, parameters.get(i)); + } + } + + /* + * The following list contains the data types supported by + * PreparedStatement but not supported by SQLContainer: + * + * [The list is provided as PreparedStatement method signatures] + * + * setNCharacterStream(int parameterIndex, Reader value) + * + * setNClob(int parameterIndex, NClob value) + * + * setNString(int parameterIndex, String value) + * + * setRef(int parameterIndex, Ref x) + * + * setRowId(int parameterIndex, RowId x) + * + * setSQLXML(int parameterIndex, SQLXML xmlObject) + * + * setBytes(int parameterIndex, byte[] x) + * + * setCharacterStream(int parameterIndex, Reader reader) + * + * setClob(int parameterIndex, Clob x) + * + * setURL(int parameterIndex, URL x) + * + * setArray(int parameterIndex, Array x) + * + * setAsciiStream(int parameterIndex, InputStream x) + * + * setBinaryStream(int parameterIndex, InputStream x) + * + * setBlob(int parameterIndex, Blob x) + */ + } + + private void handleNullValue(int i, PreparedStatement pstmt) + throws SQLException { + if (BigDecimal.class.equals(dataTypes.get(i))) { + pstmt.setBigDecimal(i + 1, null); + } else if (Boolean.class.equals(dataTypes.get(i))) { + pstmt.setNull(i + 1, Types.BOOLEAN); + } else if (Byte.class.equals(dataTypes.get(i))) { + pstmt.setNull(i + 1, Types.SMALLINT); + } else if (Date.class.equals(dataTypes.get(i))) { + pstmt.setDate(i + 1, null); + } else if (Double.class.equals(dataTypes.get(i))) { + pstmt.setNull(i + 1, Types.DOUBLE); + } else if (Float.class.equals(dataTypes.get(i))) { + pstmt.setNull(i + 1, Types.FLOAT); + } else if (Integer.class.equals(dataTypes.get(i))) { + pstmt.setNull(i + 1, Types.INTEGER); + } else if (Long.class.equals(dataTypes.get(i))) { + pstmt.setNull(i + 1, Types.BIGINT); + } else if (Short.class.equals(dataTypes.get(i))) { + pstmt.setNull(i + 1, Types.SMALLINT); + } else if (String.class.equals(dataTypes.get(i))) { + pstmt.setString(i + 1, null); + } else if (Time.class.equals(dataTypes.get(i))) { + pstmt.setTime(i + 1, null); + } else if (Timestamp.class.equals(dataTypes.get(i))) { + pstmt.setTimestamp(i + 1, null); + } else { + throw new SQLException("Data type not supported by SQLContainer: " + + parameters.get(i).getClass().toString()); + } + } +} diff --git a/src/com/vaadin/event/FieldEvents.java b/src/com/vaadin/event/FieldEvents.java index 202abba078..28fd6bb4f7 100644 --- a/src/com/vaadin/event/FieldEvents.java +++ b/src/com/vaadin/event/FieldEvents.java @@ -1,250 +1,250 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.event; - -import java.io.Serializable; -import java.lang.reflect.Method; - -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.tools.ReflectTools; -import com.vaadin.ui.Component; -import com.vaadin.ui.Field; -import com.vaadin.ui.Field.ValueChangeEvent; -import com.vaadin.ui.TextField; - -/** - * Interface that serves as a wrapper for {@link Field} related events. - */ -public interface FieldEvents { - - /** - * The interface for adding and removing FocusEvent listeners. - * By implementing this interface a class explicitly announces that it will - * generate a FocusEvent when it receives keyboard focus. - *

- * Note: The general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * addListener and removeListener methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - *

- * - * @since 6.2 - * @see FocusListener - * @see FocusEvent - */ - public interface FocusNotifier extends Serializable { - /** - * Adds a FocusListener to the Component which gets fired - * when a Field receives keyboard focus. - * - * @param listener - * @see FocusListener - * @since 6.2 - */ - public void addListener(FocusListener listener); - - /** - * Removes a FocusListener from the Component. - * - * @param listener - * @see FocusListener - * @since 6.2 - */ - public void removeListener(FocusListener listener); - } - - /** - * The interface for adding and removing BlurEvent listeners. - * By implementing this interface a class explicitly announces that it will - * generate a BlurEvent when it loses keyboard focus. - *

- * Note: The general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * addListener and removeListener methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - *

- * - * @since 6.2 - * @see BlurListener - * @see BlurEvent - */ - public interface BlurNotifier extends Serializable { - /** - * Adds a BlurListener to the Component which gets fired - * when a Field loses keyboard focus. - * - * @param listener - * @see BlurListener - * @since 6.2 - */ - public void addListener(BlurListener listener); - - /** - * Removes a BlurListener from the Component. - * - * @param listener - * @see BlurListener - * @since 6.2 - */ - public void removeListener(BlurListener listener); - } - - /** - * FocusEvent class for holding additional event information. - * Fired when a Field receives keyboard focus. - * - * @since 6.2 - */ - @SuppressWarnings("serial") - public class FocusEvent extends Component.Event { - - /** - * Identifier for event that can be used in {@link EventRouter} - */ - public static final String EVENT_ID = EventId.FOCUS; - - public FocusEvent(Component source) { - super(source); - } - } - - /** - * FocusListener interface for listening for - * FocusEvent fired by a Field. - * - * @see FocusEvent - * @since 6.2 - */ - public interface FocusListener extends ComponentEventListener { - - public static final Method focusMethod = ReflectTools.findMethod( - FocusListener.class, "focus", FocusEvent.class); - - /** - * Component has been focused - * - * @param event - * Component focus event. - */ - public void focus(FocusEvent event); - } - - /** - * BlurEvent class for holding additional event information. - * Fired when a Field loses keyboard focus. - * - * @since 6.2 - */ - @SuppressWarnings("serial") - public class BlurEvent extends Component.Event { - - /** - * Identifier for event that can be used in {@link EventRouter} - */ - public static final String EVENT_ID = EventId.BLUR; - - public BlurEvent(Component source) { - super(source); - } - } - - /** - * BlurListener interface for listening for - * BlurEvent fired by a Field. - * - * @see BlurEvent - * @since 6.2 - */ - public interface BlurListener extends ComponentEventListener { - - public static final Method blurMethod = ReflectTools.findMethod( - BlurListener.class, "blur", BlurEvent.class); - - /** - * Component has been blurred - * - * @param event - * Component blur event. - */ - public void blur(BlurEvent event); - } - - /** - * TextChangeEvents are fired when the user is editing the text content of a - * field. Most commonly text change events are triggered by typing text with - * keyboard, but e.g. pasting content from clip board to a text field also - * triggers an event. - *

- * TextChangeEvents differ from {@link ValueChangeEvent}s so that they are - * triggered repeatedly while the end user is filling the field. - * ValueChangeEvents are not fired until the user for example hits enter or - * focuses another field. Also note the difference that TextChangeEvents are - * only fired if the change is triggered from the user, while - * ValueChangeEvents are also fired if the field value is set by the - * application code. - *

- * The {@link TextChangeNotifier}s implementation may decide when exactly - * TextChangeEvents are fired. TextChangeEvents are not necessary fire for - * example on each key press, but buffered with a small delay. The - * {@link TextField} component supports different modes for triggering - * TextChangeEvents. - * - * @see TextChangeListener - * @see TextChangeNotifier - * @see TextField#setTextChangeEventMode(com.vaadin.ui.TextField.TextChangeEventMode) - * @since 6.5 - */ - public static abstract class TextChangeEvent extends Component.Event { - public TextChangeEvent(Component source) { - super(source); - } - - /** - * @return the text content of the field after the - * {@link TextChangeEvent} - */ - public abstract String getText(); - - /** - * @return the cursor position during after the {@link TextChangeEvent} - */ - public abstract int getCursorPosition(); - } - - /** - * A listener for {@link TextChangeEvent}s. - * - * @since 6.5 - */ - public interface TextChangeListener extends ComponentEventListener { - - public static String EVENT_ID = "ie"; - public static Method EVENT_METHOD = ReflectTools.findMethod( - TextChangeListener.class, "textChange", TextChangeEvent.class); - - /** - * This method is called repeatedly while the text is edited by a user. - * - * @param event - * the event providing details of the text change - */ - public void textChange(TextChangeEvent event); - } - - /** - * An interface implemented by a {@link Field} supporting - * {@link TextChangeEvent}s. An example a {@link TextField} supports - * {@link TextChangeListener}s. - */ - public interface TextChangeNotifier extends Serializable { - public void addListener(TextChangeListener listener); - - public void removeListener(TextChangeListener listener); - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.event; + +import java.io.Serializable; +import java.lang.reflect.Method; + +import com.vaadin.terminal.gwt.client.EventId; +import com.vaadin.tools.ReflectTools; +import com.vaadin.ui.Component; +import com.vaadin.ui.Field; +import com.vaadin.ui.Field.ValueChangeEvent; +import com.vaadin.ui.TextField; + +/** + * Interface that serves as a wrapper for {@link Field} related events. + */ +public interface FieldEvents { + + /** + * The interface for adding and removing FocusEvent listeners. + * By implementing this interface a class explicitly announces that it will + * generate a FocusEvent when it receives keyboard focus. + *

+ * Note: The general Java convention is not to explicitly declare that a + * class generates events, but to directly define the + * addListener and removeListener methods. That + * way the caller of these methods has no real way of finding out if the + * class really will send the events, or if it just defines the methods to + * be able to implement an interface. + *

+ * + * @since 6.2 + * @see FocusListener + * @see FocusEvent + */ + public interface FocusNotifier extends Serializable { + /** + * Adds a FocusListener to the Component which gets fired + * when a Field receives keyboard focus. + * + * @param listener + * @see FocusListener + * @since 6.2 + */ + public void addListener(FocusListener listener); + + /** + * Removes a FocusListener from the Component. + * + * @param listener + * @see FocusListener + * @since 6.2 + */ + public void removeListener(FocusListener listener); + } + + /** + * The interface for adding and removing BlurEvent listeners. + * By implementing this interface a class explicitly announces that it will + * generate a BlurEvent when it loses keyboard focus. + *

+ * Note: The general Java convention is not to explicitly declare that a + * class generates events, but to directly define the + * addListener and removeListener methods. That + * way the caller of these methods has no real way of finding out if the + * class really will send the events, or if it just defines the methods to + * be able to implement an interface. + *

+ * + * @since 6.2 + * @see BlurListener + * @see BlurEvent + */ + public interface BlurNotifier extends Serializable { + /** + * Adds a BlurListener to the Component which gets fired + * when a Field loses keyboard focus. + * + * @param listener + * @see BlurListener + * @since 6.2 + */ + public void addListener(BlurListener listener); + + /** + * Removes a BlurListener from the Component. + * + * @param listener + * @see BlurListener + * @since 6.2 + */ + public void removeListener(BlurListener listener); + } + + /** + * FocusEvent class for holding additional event information. + * Fired when a Field receives keyboard focus. + * + * @since 6.2 + */ + @SuppressWarnings("serial") + public class FocusEvent extends Component.Event { + + /** + * Identifier for event that can be used in {@link EventRouter} + */ + public static final String EVENT_ID = EventId.FOCUS; + + public FocusEvent(Component source) { + super(source); + } + } + + /** + * FocusListener interface for listening for + * FocusEvent fired by a Field. + * + * @see FocusEvent + * @since 6.2 + */ + public interface FocusListener extends ComponentEventListener { + + public static final Method focusMethod = ReflectTools.findMethod( + FocusListener.class, "focus", FocusEvent.class); + + /** + * Component has been focused + * + * @param event + * Component focus event. + */ + public void focus(FocusEvent event); + } + + /** + * BlurEvent class for holding additional event information. + * Fired when a Field loses keyboard focus. + * + * @since 6.2 + */ + @SuppressWarnings("serial") + public class BlurEvent extends Component.Event { + + /** + * Identifier for event that can be used in {@link EventRouter} + */ + public static final String EVENT_ID = EventId.BLUR; + + public BlurEvent(Component source) { + super(source); + } + } + + /** + * BlurListener interface for listening for + * BlurEvent fired by a Field. + * + * @see BlurEvent + * @since 6.2 + */ + public interface BlurListener extends ComponentEventListener { + + public static final Method blurMethod = ReflectTools.findMethod( + BlurListener.class, "blur", BlurEvent.class); + + /** + * Component has been blurred + * + * @param event + * Component blur event. + */ + public void blur(BlurEvent event); + } + + /** + * TextChangeEvents are fired when the user is editing the text content of a + * field. Most commonly text change events are triggered by typing text with + * keyboard, but e.g. pasting content from clip board to a text field also + * triggers an event. + *

+ * TextChangeEvents differ from {@link ValueChangeEvent}s so that they are + * triggered repeatedly while the end user is filling the field. + * ValueChangeEvents are not fired until the user for example hits enter or + * focuses another field. Also note the difference that TextChangeEvents are + * only fired if the change is triggered from the user, while + * ValueChangeEvents are also fired if the field value is set by the + * application code. + *

+ * The {@link TextChangeNotifier}s implementation may decide when exactly + * TextChangeEvents are fired. TextChangeEvents are not necessary fire for + * example on each key press, but buffered with a small delay. The + * {@link TextField} component supports different modes for triggering + * TextChangeEvents. + * + * @see TextChangeListener + * @see TextChangeNotifier + * @see TextField#setTextChangeEventMode(com.vaadin.ui.TextField.TextChangeEventMode) + * @since 6.5 + */ + public static abstract class TextChangeEvent extends Component.Event { + public TextChangeEvent(Component source) { + super(source); + } + + /** + * @return the text content of the field after the + * {@link TextChangeEvent} + */ + public abstract String getText(); + + /** + * @return the cursor position during after the {@link TextChangeEvent} + */ + public abstract int getCursorPosition(); + } + + /** + * A listener for {@link TextChangeEvent}s. + * + * @since 6.5 + */ + public interface TextChangeListener extends ComponentEventListener { + + public static String EVENT_ID = "ie"; + public static Method EVENT_METHOD = ReflectTools.findMethod( + TextChangeListener.class, "textChange", TextChangeEvent.class); + + /** + * This method is called repeatedly while the text is edited by a user. + * + * @param event + * the event providing details of the text change + */ + public void textChange(TextChangeEvent event); + } + + /** + * An interface implemented by a {@link Field} supporting + * {@link TextChangeEvent}s. An example a {@link TextField} supports + * {@link TextChangeListener}s. + */ + public interface TextChangeNotifier extends Serializable { + public void addListener(TextChangeListener listener); + + public void removeListener(TextChangeListener listener); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/DateTimeService.java b/src/com/vaadin/terminal/gwt/client/DateTimeService.java index d368d655af..c0151d2819 100644 --- a/src/com/vaadin/terminal/gwt/client/DateTimeService.java +++ b/src/com/vaadin/terminal/gwt/client/DateTimeService.java @@ -1,439 +1,439 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client; - -import java.util.Date; - -import com.google.gwt.i18n.client.DateTimeFormat; -import com.google.gwt.i18n.client.LocaleInfo; -import com.vaadin.terminal.gwt.client.ui.VDateField; - -/** - * This class provides date/time parsing services to all components on the - * client side. - * - * @author Vaadin Ltd. - * - */ -@SuppressWarnings("deprecation") -public class DateTimeService { - - private String currentLocale; - - private static int[] maxDaysInMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, - 31, 30, 31 }; - - /** - * Creates a new date time service with the application default locale. - */ - public DateTimeService() { - currentLocale = LocaleService.getDefaultLocale(); - } - - /** - * Creates a new date time service with a given locale. - * - * @param locale - * e.g. fi, en etc. - * @throws LocaleNotLoadedException - */ - public DateTimeService(String locale) throws LocaleNotLoadedException { - setLocale(locale); - } - - public void setLocale(String locale) throws LocaleNotLoadedException { - if (LocaleService.getAvailableLocales().contains(locale)) { - currentLocale = locale; - } else { - throw new LocaleNotLoadedException(locale); - } - } - - public String getLocale() { - return currentLocale; - } - - public String getMonth(int month) { - try { - return LocaleService.getMonthNames(currentLocale)[month]; - } catch (final LocaleNotLoadedException e) { - VConsole.error(e); - return null; - } - } - - public String getShortMonth(int month) { - try { - return LocaleService.getShortMonthNames(currentLocale)[month]; - } catch (final LocaleNotLoadedException e) { - VConsole.error(e); - return null; - } - } - - public String getDay(int day) { - try { - return LocaleService.getDayNames(currentLocale)[day]; - } catch (final LocaleNotLoadedException e) { - VConsole.error(e); - return null; - } - } - - public String getShortDay(int day) { - try { - return LocaleService.getShortDayNames(currentLocale)[day]; - } catch (final LocaleNotLoadedException e) { - VConsole.error(e); - return null; - } - } - - public int getFirstDayOfWeek() { - try { - return LocaleService.getFirstDayOfWeek(currentLocale); - } catch (final LocaleNotLoadedException e) { - VConsole.error(e); - return 0; - } - } - - public boolean isTwelveHourClock() { - try { - return LocaleService.isTwelveHourClock(currentLocale); - } catch (final LocaleNotLoadedException e) { - VConsole.error(e); - return false; - } - } - - public String getClockDelimeter() { - try { - return LocaleService.getClockDelimiter(currentLocale); - } catch (final LocaleNotLoadedException e) { - VConsole.error(e); - return ":"; - } - } - - private static final String[] DEFAULT_AMPM_STRINGS = { "AM", "PM" }; - - public String[] getAmPmStrings() { - try { - return LocaleService.getAmPmStrings(currentLocale); - } catch (final LocaleNotLoadedException e) { - // TODO can this practically even happen? Should die instead? - VConsole.error("Locale not loaded, using fallback : AM/PM"); - VConsole.error(e); - return DEFAULT_AMPM_STRINGS; - } - } - - public int getStartWeekDay(Date date) { - final Date dateForFirstOfThisMonth = new Date(date.getYear(), - date.getMonth(), 1); - int firstDay; - try { - firstDay = LocaleService.getFirstDayOfWeek(currentLocale); - } catch (final LocaleNotLoadedException e) { - VConsole.error("Locale not loaded, using fallback 0"); - VConsole.error(e); - firstDay = 0; - } - int start = dateForFirstOfThisMonth.getDay() - firstDay; - if (start < 0) { - start = 6; - } - return start; - } - - public static void setMilliseconds(Date date, int ms) { - date.setTime(date.getTime() / 1000 * 1000 + ms); - } - - public static int getMilliseconds(Date date) { - if (date == null) { - return 0; - } - - return (int) (date.getTime() - date.getTime() / 1000 * 1000); - } - - public static int getNumberOfDaysInMonth(Date date) { - final int month = date.getMonth(); - if (month == 1 && true == isLeapYear(date)) { - return 29; - } - return maxDaysInMonth[month]; - } - - public static boolean isLeapYear(Date date) { - // Instantiate the date for 1st March of that year - final Date firstMarch = new Date(date.getYear(), 2, 1); - - // Go back 1 day - final long firstMarchTime = firstMarch.getTime(); - final long lastDayTimeFeb = firstMarchTime - (24 * 60 * 60 * 1000); // NUM_MILLISECS_A_DAY - - // Instantiate new Date with this time - final Date febLastDay = new Date(lastDayTimeFeb); - - // Check for date in this new instance - return (29 == febLastDay.getDate()) ? true : false; - } - - public static boolean isSameDay(Date d1, Date d2) { - return (getDayInt(d1) == getDayInt(d2)); - } - - public static boolean isInRange(Date date, Date rangeStart, Date rangeEnd, - int resolution) { - Date s; - Date e; - if (rangeStart.after(rangeEnd)) { - s = rangeEnd; - e = rangeStart; - } else { - e = rangeEnd; - s = rangeStart; - } - long start = s.getYear() * 10000000000l; - long end = e.getYear() * 10000000000l; - long target = date.getYear() * 10000000000l; - - if (resolution == VDateField.RESOLUTION_YEAR) { - return (start <= target && end >= target); - } - start += s.getMonth() * 100000000l; - end += e.getMonth() * 100000000l; - target += date.getMonth() * 100000000l; - if (resolution == VDateField.RESOLUTION_MONTH) { - return (start <= target && end >= target); - } - start += s.getDate() * 1000000l; - end += e.getDate() * 1000000l; - target += date.getDate() * 1000000l; - if (resolution == VDateField.RESOLUTION_DAY) { - return (start <= target && end >= target); - } - start += s.getHours() * 10000l; - end += e.getHours() * 10000l; - target += date.getHours() * 10000l; - if (resolution == VDateField.RESOLUTION_HOUR) { - return (start <= target && end >= target); - } - start += s.getMinutes() * 100l; - end += e.getMinutes() * 100l; - target += date.getMinutes() * 100l; - if (resolution == VDateField.RESOLUTION_MIN) { - return (start <= target && end >= target); - } - start += s.getSeconds(); - end += e.getSeconds(); - target += date.getSeconds(); - return (start <= target && end >= target); - - } - - private static int getDayInt(Date date) { - final int y = date.getYear(); - final int m = date.getMonth(); - final int d = date.getDate(); - - return ((y + 1900) * 10000 + m * 100 + d) * 1000000000; - } - - /** - * Returns the ISO-8601 week number of the given date. - * - * @param date - * The date for which the week number should be resolved - * @return The ISO-8601 week number for {@literal date} - */ - public static int getISOWeekNumber(Date date) { - final long MILLISECONDS_PER_DAY = 24 * 3600 * 1000; - int dayOfWeek = date.getDay(); // 0 == sunday - - // ISO 8601 use weeks that start on monday so we use - // mon=1,tue=2,...sun=7; - if (dayOfWeek == 0) { - dayOfWeek = 7; - } - // Find nearest thursday (defines the week in ISO 8601). The week number - // for the nearest thursday is the same as for the target date. - int nearestThursdayDiff = 4 - dayOfWeek; // 4 is thursday - Date nearestThursday = new Date(date.getTime() + nearestThursdayDiff - * MILLISECONDS_PER_DAY); - - Date firstOfJanuary = new Date(nearestThursday.getYear(), 0, 1); - long timeDiff = nearestThursday.getTime() - firstOfJanuary.getTime(); - int daysSinceFirstOfJanuary = (int) (timeDiff / MILLISECONDS_PER_DAY); - - int weekNumber = (daysSinceFirstOfJanuary) / 7 + 1; - - return weekNumber; - } - - /** - * Check if format contains the month name. If it does we manually convert - * it to the month name since DateTimeFormat.format always uses the current - * locale and will replace the month name wrong if current locale is - * different from the locale set for the DateField. - * - * MMMM is converted into long month name, MMM is converted into short month - * name. '' are added around the name to avoid that DateTimeFormat parses - * the month name as a pattern. - * - * @param date - * The date to convert - * @param formatStr - * The format string that might contain MMM or MMMM - * @param dateTimeService - * Reference to the Vaadin DateTimeService - * @return - */ - public String formatDate(Date date, String formatStr) { - /* - * Format month names separately when locale for the DateTimeService is - * not the same as the browser locale - */ - formatStr = formatMonthNames(date, formatStr); - - // Format uses the browser locale - DateTimeFormat format = DateTimeFormat.getFormat(formatStr); - - String result = format.format(date); - - return result; - } - - private String formatMonthNames(Date date, String formatStr) { - if (formatStr.contains("MMMM")) { - String monthName = getMonth(date.getMonth()); - - if (monthName != null) { - /* - * Replace 4 or more M:s with the quoted month name. Also - * concatenate generated string with any other string prepending - * or following the MMMM pattern, i.e. 'MMMM'ta ' becomes - * 'MONTHta ' and not 'MONTH''ta ', 'ab'MMMM becomes 'abMONTH', - * 'x'MMMM'y' becomes 'xMONTHy'. - */ - formatStr = formatStr.replaceAll("'([M]{4,})'", monthName); - formatStr = formatStr.replaceAll("([M]{4,})'", "'" + monthName); - formatStr = formatStr.replaceAll("'([M]{4,})", monthName + "'"); - formatStr = formatStr.replaceAll("[M]{4,}", "'" + monthName - + "'"); - } - } - - if (formatStr.contains("MMM")) { - - String monthName = getShortMonth(date.getMonth()); - - if (monthName != null) { - /* - * Replace 3 or more M:s with the quoted month name. Also - * concatenate generated string with any other string prepending - * or following the MMM pattern, i.e. 'MMM'ta ' becomes 'MONTHta - * ' and not 'MONTH''ta ', 'ab'MMM becomes 'abMONTH', 'x'MMM'y' - * becomes 'xMONTHy'. - */ - formatStr = formatStr.replaceAll("'([M]{3,})'", monthName); - formatStr = formatStr.replaceAll("([M]{3,})'", "'" + monthName); - formatStr = formatStr.replaceAll("'([M]{3,})", monthName + "'"); - formatStr = formatStr.replaceAll("[M]{3,}", "'" + monthName - + "'"); - } - } - - return formatStr; - } - - /** - * Replaces month names in the entered date with the name in the current - * browser locale. - * - * @param enteredDate - * Date string e.g. "5 May 2010" - * @param formatString - * Format string e.g. "d M yyyy" - * @return The date string where the month names have been replaced by the - * browser locale version - */ - private String parseMonthName(String enteredDate, String formatString) { - LocaleInfo browserLocale = LocaleInfo.getCurrentLocale(); - if (browserLocale.getLocaleName().equals(getLocale())) { - // No conversion needs to be done when locales match - return enteredDate; - } - String[] browserMonthNames = browserLocale.getDateTimeConstants() - .months(); - String[] browserShortMonthNames = browserLocale.getDateTimeConstants() - .shortMonths(); - - if (formatString.contains("MMMM")) { - // Full month name - for (int i = 0; i < 12; i++) { - enteredDate = enteredDate.replaceAll(getMonth(i), - browserMonthNames[i]); - } - } - if (formatString.contains("MMM")) { - // Short month name - for (int i = 0; i < 12; i++) { - enteredDate = enteredDate.replaceAll(getShortMonth(i), - browserShortMonthNames[i]); - } - } - - return enteredDate; - } - - /** - * Parses the given date string using the given format string and the locale - * set in this DateTimeService instance. - * - * @param dateString - * Date string e.g. "1 February 2010" - * @param formatString - * Format string e.g. "d MMMM yyyy" - * @param lenient - * true to use lenient parsing, false to use strict parsing - * @return A Date object representing the dateString. Never returns null. - * @throws IllegalArgumentException - * if the parsing fails - * - */ - public Date parseDate(String dateString, String formatString, - boolean lenient) throws IllegalArgumentException { - /* DateTimeFormat uses the browser's locale */ - DateTimeFormat format = DateTimeFormat.getFormat(formatString); - - /* - * Parse month names separately when locale for the DateTimeService is - * not the same as the browser locale - */ - dateString = parseMonthName(dateString, formatString); - - Date date; - - if (lenient) { - date = format.parse(dateString); - } else { - date = format.parseStrict(dateString); - } - - // Some version of Firefox sets the timestamp to 0 if parsing fails. - if (date != null && date.getTime() == 0) { - throw new IllegalArgumentException("Parsing of '" + dateString - + "' failed"); - } - - return date; - - } - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client; + +import java.util.Date; + +import com.google.gwt.i18n.client.DateTimeFormat; +import com.google.gwt.i18n.client.LocaleInfo; +import com.vaadin.terminal.gwt.client.ui.VDateField; + +/** + * This class provides date/time parsing services to all components on the + * client side. + * + * @author Vaadin Ltd. + * + */ +@SuppressWarnings("deprecation") +public class DateTimeService { + + private String currentLocale; + + private static int[] maxDaysInMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, + 31, 30, 31 }; + + /** + * Creates a new date time service with the application default locale. + */ + public DateTimeService() { + currentLocale = LocaleService.getDefaultLocale(); + } + + /** + * Creates a new date time service with a given locale. + * + * @param locale + * e.g. fi, en etc. + * @throws LocaleNotLoadedException + */ + public DateTimeService(String locale) throws LocaleNotLoadedException { + setLocale(locale); + } + + public void setLocale(String locale) throws LocaleNotLoadedException { + if (LocaleService.getAvailableLocales().contains(locale)) { + currentLocale = locale; + } else { + throw new LocaleNotLoadedException(locale); + } + } + + public String getLocale() { + return currentLocale; + } + + public String getMonth(int month) { + try { + return LocaleService.getMonthNames(currentLocale)[month]; + } catch (final LocaleNotLoadedException e) { + VConsole.error(e); + return null; + } + } + + public String getShortMonth(int month) { + try { + return LocaleService.getShortMonthNames(currentLocale)[month]; + } catch (final LocaleNotLoadedException e) { + VConsole.error(e); + return null; + } + } + + public String getDay(int day) { + try { + return LocaleService.getDayNames(currentLocale)[day]; + } catch (final LocaleNotLoadedException e) { + VConsole.error(e); + return null; + } + } + + public String getShortDay(int day) { + try { + return LocaleService.getShortDayNames(currentLocale)[day]; + } catch (final LocaleNotLoadedException e) { + VConsole.error(e); + return null; + } + } + + public int getFirstDayOfWeek() { + try { + return LocaleService.getFirstDayOfWeek(currentLocale); + } catch (final LocaleNotLoadedException e) { + VConsole.error(e); + return 0; + } + } + + public boolean isTwelveHourClock() { + try { + return LocaleService.isTwelveHourClock(currentLocale); + } catch (final LocaleNotLoadedException e) { + VConsole.error(e); + return false; + } + } + + public String getClockDelimeter() { + try { + return LocaleService.getClockDelimiter(currentLocale); + } catch (final LocaleNotLoadedException e) { + VConsole.error(e); + return ":"; + } + } + + private static final String[] DEFAULT_AMPM_STRINGS = { "AM", "PM" }; + + public String[] getAmPmStrings() { + try { + return LocaleService.getAmPmStrings(currentLocale); + } catch (final LocaleNotLoadedException e) { + // TODO can this practically even happen? Should die instead? + VConsole.error("Locale not loaded, using fallback : AM/PM"); + VConsole.error(e); + return DEFAULT_AMPM_STRINGS; + } + } + + public int getStartWeekDay(Date date) { + final Date dateForFirstOfThisMonth = new Date(date.getYear(), + date.getMonth(), 1); + int firstDay; + try { + firstDay = LocaleService.getFirstDayOfWeek(currentLocale); + } catch (final LocaleNotLoadedException e) { + VConsole.error("Locale not loaded, using fallback 0"); + VConsole.error(e); + firstDay = 0; + } + int start = dateForFirstOfThisMonth.getDay() - firstDay; + if (start < 0) { + start = 6; + } + return start; + } + + public static void setMilliseconds(Date date, int ms) { + date.setTime(date.getTime() / 1000 * 1000 + ms); + } + + public static int getMilliseconds(Date date) { + if (date == null) { + return 0; + } + + return (int) (date.getTime() - date.getTime() / 1000 * 1000); + } + + public static int getNumberOfDaysInMonth(Date date) { + final int month = date.getMonth(); + if (month == 1 && true == isLeapYear(date)) { + return 29; + } + return maxDaysInMonth[month]; + } + + public static boolean isLeapYear(Date date) { + // Instantiate the date for 1st March of that year + final Date firstMarch = new Date(date.getYear(), 2, 1); + + // Go back 1 day + final long firstMarchTime = firstMarch.getTime(); + final long lastDayTimeFeb = firstMarchTime - (24 * 60 * 60 * 1000); // NUM_MILLISECS_A_DAY + + // Instantiate new Date with this time + final Date febLastDay = new Date(lastDayTimeFeb); + + // Check for date in this new instance + return (29 == febLastDay.getDate()) ? true : false; + } + + public static boolean isSameDay(Date d1, Date d2) { + return (getDayInt(d1) == getDayInt(d2)); + } + + public static boolean isInRange(Date date, Date rangeStart, Date rangeEnd, + int resolution) { + Date s; + Date e; + if (rangeStart.after(rangeEnd)) { + s = rangeEnd; + e = rangeStart; + } else { + e = rangeEnd; + s = rangeStart; + } + long start = s.getYear() * 10000000000l; + long end = e.getYear() * 10000000000l; + long target = date.getYear() * 10000000000l; + + if (resolution == VDateField.RESOLUTION_YEAR) { + return (start <= target && end >= target); + } + start += s.getMonth() * 100000000l; + end += e.getMonth() * 100000000l; + target += date.getMonth() * 100000000l; + if (resolution == VDateField.RESOLUTION_MONTH) { + return (start <= target && end >= target); + } + start += s.getDate() * 1000000l; + end += e.getDate() * 1000000l; + target += date.getDate() * 1000000l; + if (resolution == VDateField.RESOLUTION_DAY) { + return (start <= target && end >= target); + } + start += s.getHours() * 10000l; + end += e.getHours() * 10000l; + target += date.getHours() * 10000l; + if (resolution == VDateField.RESOLUTION_HOUR) { + return (start <= target && end >= target); + } + start += s.getMinutes() * 100l; + end += e.getMinutes() * 100l; + target += date.getMinutes() * 100l; + if (resolution == VDateField.RESOLUTION_MIN) { + return (start <= target && end >= target); + } + start += s.getSeconds(); + end += e.getSeconds(); + target += date.getSeconds(); + return (start <= target && end >= target); + + } + + private static int getDayInt(Date date) { + final int y = date.getYear(); + final int m = date.getMonth(); + final int d = date.getDate(); + + return ((y + 1900) * 10000 + m * 100 + d) * 1000000000; + } + + /** + * Returns the ISO-8601 week number of the given date. + * + * @param date + * The date for which the week number should be resolved + * @return The ISO-8601 week number for {@literal date} + */ + public static int getISOWeekNumber(Date date) { + final long MILLISECONDS_PER_DAY = 24 * 3600 * 1000; + int dayOfWeek = date.getDay(); // 0 == sunday + + // ISO 8601 use weeks that start on monday so we use + // mon=1,tue=2,...sun=7; + if (dayOfWeek == 0) { + dayOfWeek = 7; + } + // Find nearest thursday (defines the week in ISO 8601). The week number + // for the nearest thursday is the same as for the target date. + int nearestThursdayDiff = 4 - dayOfWeek; // 4 is thursday + Date nearestThursday = new Date(date.getTime() + nearestThursdayDiff + * MILLISECONDS_PER_DAY); + + Date firstOfJanuary = new Date(nearestThursday.getYear(), 0, 1); + long timeDiff = nearestThursday.getTime() - firstOfJanuary.getTime(); + int daysSinceFirstOfJanuary = (int) (timeDiff / MILLISECONDS_PER_DAY); + + int weekNumber = (daysSinceFirstOfJanuary) / 7 + 1; + + return weekNumber; + } + + /** + * Check if format contains the month name. If it does we manually convert + * it to the month name since DateTimeFormat.format always uses the current + * locale and will replace the month name wrong if current locale is + * different from the locale set for the DateField. + * + * MMMM is converted into long month name, MMM is converted into short month + * name. '' are added around the name to avoid that DateTimeFormat parses + * the month name as a pattern. + * + * @param date + * The date to convert + * @param formatStr + * The format string that might contain MMM or MMMM + * @param dateTimeService + * Reference to the Vaadin DateTimeService + * @return + */ + public String formatDate(Date date, String formatStr) { + /* + * Format month names separately when locale for the DateTimeService is + * not the same as the browser locale + */ + formatStr = formatMonthNames(date, formatStr); + + // Format uses the browser locale + DateTimeFormat format = DateTimeFormat.getFormat(formatStr); + + String result = format.format(date); + + return result; + } + + private String formatMonthNames(Date date, String formatStr) { + if (formatStr.contains("MMMM")) { + String monthName = getMonth(date.getMonth()); + + if (monthName != null) { + /* + * Replace 4 or more M:s with the quoted month name. Also + * concatenate generated string with any other string prepending + * or following the MMMM pattern, i.e. 'MMMM'ta ' becomes + * 'MONTHta ' and not 'MONTH''ta ', 'ab'MMMM becomes 'abMONTH', + * 'x'MMMM'y' becomes 'xMONTHy'. + */ + formatStr = formatStr.replaceAll("'([M]{4,})'", monthName); + formatStr = formatStr.replaceAll("([M]{4,})'", "'" + monthName); + formatStr = formatStr.replaceAll("'([M]{4,})", monthName + "'"); + formatStr = formatStr.replaceAll("[M]{4,}", "'" + monthName + + "'"); + } + } + + if (formatStr.contains("MMM")) { + + String monthName = getShortMonth(date.getMonth()); + + if (monthName != null) { + /* + * Replace 3 or more M:s with the quoted month name. Also + * concatenate generated string with any other string prepending + * or following the MMM pattern, i.e. 'MMM'ta ' becomes 'MONTHta + * ' and not 'MONTH''ta ', 'ab'MMM becomes 'abMONTH', 'x'MMM'y' + * becomes 'xMONTHy'. + */ + formatStr = formatStr.replaceAll("'([M]{3,})'", monthName); + formatStr = formatStr.replaceAll("([M]{3,})'", "'" + monthName); + formatStr = formatStr.replaceAll("'([M]{3,})", monthName + "'"); + formatStr = formatStr.replaceAll("[M]{3,}", "'" + monthName + + "'"); + } + } + + return formatStr; + } + + /** + * Replaces month names in the entered date with the name in the current + * browser locale. + * + * @param enteredDate + * Date string e.g. "5 May 2010" + * @param formatString + * Format string e.g. "d M yyyy" + * @return The date string where the month names have been replaced by the + * browser locale version + */ + private String parseMonthName(String enteredDate, String formatString) { + LocaleInfo browserLocale = LocaleInfo.getCurrentLocale(); + if (browserLocale.getLocaleName().equals(getLocale())) { + // No conversion needs to be done when locales match + return enteredDate; + } + String[] browserMonthNames = browserLocale.getDateTimeConstants() + .months(); + String[] browserShortMonthNames = browserLocale.getDateTimeConstants() + .shortMonths(); + + if (formatString.contains("MMMM")) { + // Full month name + for (int i = 0; i < 12; i++) { + enteredDate = enteredDate.replaceAll(getMonth(i), + browserMonthNames[i]); + } + } + if (formatString.contains("MMM")) { + // Short month name + for (int i = 0; i < 12; i++) { + enteredDate = enteredDate.replaceAll(getShortMonth(i), + browserShortMonthNames[i]); + } + } + + return enteredDate; + } + + /** + * Parses the given date string using the given format string and the locale + * set in this DateTimeService instance. + * + * @param dateString + * Date string e.g. "1 February 2010" + * @param formatString + * Format string e.g. "d MMMM yyyy" + * @param lenient + * true to use lenient parsing, false to use strict parsing + * @return A Date object representing the dateString. Never returns null. + * @throws IllegalArgumentException + * if the parsing fails + * + */ + public Date parseDate(String dateString, String formatString, + boolean lenient) throws IllegalArgumentException { + /* DateTimeFormat uses the browser's locale */ + DateTimeFormat format = DateTimeFormat.getFormat(formatString); + + /* + * Parse month names separately when locale for the DateTimeService is + * not the same as the browser locale + */ + dateString = parseMonthName(dateString, formatString); + + Date date; + + if (lenient) { + date = format.parse(dateString); + } else { + date = format.parseStrict(dateString); + } + + // Some version of Firefox sets the timestamp to 0 if parsing fails. + if (date != null && date.getTime() == 0) { + throw new IllegalArgumentException("Parsing of '" + dateString + + "' failed"); + } + + return date; + + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/LocaleNotLoadedException.java b/src/com/vaadin/terminal/gwt/client/LocaleNotLoadedException.java index 4d0a9faf97..871495c79e 100644 --- a/src/com/vaadin/terminal/gwt/client/LocaleNotLoadedException.java +++ b/src/com/vaadin/terminal/gwt/client/LocaleNotLoadedException.java @@ -1,13 +1,13 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client; - -@SuppressWarnings("serial") -public class LocaleNotLoadedException extends Exception { - - public LocaleNotLoadedException(String locale) { - super(locale); - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client; + +@SuppressWarnings("serial") +public class LocaleNotLoadedException extends Exception { + + public LocaleNotLoadedException(String locale) { + super(locale); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/LocaleService.java b/src/com/vaadin/terminal/gwt/client/LocaleService.java index 9ae1b04118..0f22ae705b 100644 --- a/src/com/vaadin/terminal/gwt/client/LocaleService.java +++ b/src/com/vaadin/terminal/gwt/client/LocaleService.java @@ -1,148 +1,148 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import com.google.gwt.core.client.JsArray; - -/** - * Date / time etc. localisation service for all widgets. Caches all loaded - * locales as JSONObjects. - * - * @author Vaadin Ltd. - * - */ -public class LocaleService { - - private static Map cache = new HashMap(); - private static String defaultLocale; - - public static void addLocale(ValueMap valueMap) { - - final String key = valueMap.getString("name"); - if (cache.containsKey(key)) { - cache.remove(key); - } - cache.put(key, valueMap); - if (cache.size() == 1) { - setDefaultLocale(key); - } - } - - public static void setDefaultLocale(String locale) { - defaultLocale = locale; - } - - public static String getDefaultLocale() { - return defaultLocale; - } - - public static Set getAvailableLocales() { - return cache.keySet(); - } - - public static String[] getMonthNames(String locale) - throws LocaleNotLoadedException { - if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getStringArray("mn"); - } else { - throw new LocaleNotLoadedException(locale); - } - } - - public static String[] getShortMonthNames(String locale) - throws LocaleNotLoadedException { - if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getStringArray("smn"); - } else { - throw new LocaleNotLoadedException(locale); - } - } - - public static String[] getDayNames(String locale) - throws LocaleNotLoadedException { - if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getStringArray("dn"); - } else { - throw new LocaleNotLoadedException(locale); - } - } - - public static String[] getShortDayNames(String locale) - throws LocaleNotLoadedException { - if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getStringArray("sdn"); - } else { - throw new LocaleNotLoadedException(locale); - } - } - - public static int getFirstDayOfWeek(String locale) - throws LocaleNotLoadedException { - if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getInt("fdow"); - } else { - throw new LocaleNotLoadedException(locale); - } - } - - public static String getDateFormat(String locale) - throws LocaleNotLoadedException { - if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getString("df"); - } else { - throw new LocaleNotLoadedException(locale); - } - } - - public static boolean isTwelveHourClock(String locale) - throws LocaleNotLoadedException { - if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getBoolean("thc"); - } else { - throw new LocaleNotLoadedException(locale); - } - } - - public static String getClockDelimiter(String locale) - throws LocaleNotLoadedException { - if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getString("hmd"); - } else { - throw new LocaleNotLoadedException(locale); - } - } - - public static String[] getAmPmStrings(String locale) - throws LocaleNotLoadedException { - if (cache.containsKey(locale)) { - final ValueMap l = cache.get(locale); - return l.getStringArray("ampm"); - } else { - throw new LocaleNotLoadedException(locale); - } - - } - - public static void addLocales(JsArray valueMapArray) { - for (int i = 0; i < valueMapArray.length(); i++) { - addLocale(valueMapArray.get(i)); - - } - - } - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.google.gwt.core.client.JsArray; + +/** + * Date / time etc. localisation service for all widgets. Caches all loaded + * locales as JSONObjects. + * + * @author Vaadin Ltd. + * + */ +public class LocaleService { + + private static Map cache = new HashMap(); + private static String defaultLocale; + + public static void addLocale(ValueMap valueMap) { + + final String key = valueMap.getString("name"); + if (cache.containsKey(key)) { + cache.remove(key); + } + cache.put(key, valueMap); + if (cache.size() == 1) { + setDefaultLocale(key); + } + } + + public static void setDefaultLocale(String locale) { + defaultLocale = locale; + } + + public static String getDefaultLocale() { + return defaultLocale; + } + + public static Set getAvailableLocales() { + return cache.keySet(); + } + + public static String[] getMonthNames(String locale) + throws LocaleNotLoadedException { + if (cache.containsKey(locale)) { + final ValueMap l = cache.get(locale); + return l.getStringArray("mn"); + } else { + throw new LocaleNotLoadedException(locale); + } + } + + public static String[] getShortMonthNames(String locale) + throws LocaleNotLoadedException { + if (cache.containsKey(locale)) { + final ValueMap l = cache.get(locale); + return l.getStringArray("smn"); + } else { + throw new LocaleNotLoadedException(locale); + } + } + + public static String[] getDayNames(String locale) + throws LocaleNotLoadedException { + if (cache.containsKey(locale)) { + final ValueMap l = cache.get(locale); + return l.getStringArray("dn"); + } else { + throw new LocaleNotLoadedException(locale); + } + } + + public static String[] getShortDayNames(String locale) + throws LocaleNotLoadedException { + if (cache.containsKey(locale)) { + final ValueMap l = cache.get(locale); + return l.getStringArray("sdn"); + } else { + throw new LocaleNotLoadedException(locale); + } + } + + public static int getFirstDayOfWeek(String locale) + throws LocaleNotLoadedException { + if (cache.containsKey(locale)) { + final ValueMap l = cache.get(locale); + return l.getInt("fdow"); + } else { + throw new LocaleNotLoadedException(locale); + } + } + + public static String getDateFormat(String locale) + throws LocaleNotLoadedException { + if (cache.containsKey(locale)) { + final ValueMap l = cache.get(locale); + return l.getString("df"); + } else { + throw new LocaleNotLoadedException(locale); + } + } + + public static boolean isTwelveHourClock(String locale) + throws LocaleNotLoadedException { + if (cache.containsKey(locale)) { + final ValueMap l = cache.get(locale); + return l.getBoolean("thc"); + } else { + throw new LocaleNotLoadedException(locale); + } + } + + public static String getClockDelimiter(String locale) + throws LocaleNotLoadedException { + if (cache.containsKey(locale)) { + final ValueMap l = cache.get(locale); + return l.getString("hmd"); + } else { + throw new LocaleNotLoadedException(locale); + } + } + + public static String[] getAmPmStrings(String locale) + throws LocaleNotLoadedException { + if (cache.containsKey(locale)) { + final ValueMap l = cache.get(locale); + return l.getStringArray("ampm"); + } else { + throw new LocaleNotLoadedException(locale); + } + + } + + public static void addLocales(JsArray valueMapArray) { + for (int i = 0; i < valueMapArray.length(); i++) { + addLocale(valueMapArray.get(i)); + + } + + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java b/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java index e1189ccb14..aaef981bab 100644 --- a/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java +++ b/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java @@ -1,305 +1,305 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client; - -import java.io.Serializable; - -import com.vaadin.terminal.gwt.server.WebBrowser; - -/** - * Class that parses the user agent string from the browser and provides - * information about the browser. Used internally by {@link BrowserInfo} and - * {@link WebBrowser}. Should not be used directly. - * - * @author Vaadin Ltd. - * @version @VERSION@ - * @since 6.3 - */ -public class VBrowserDetails implements Serializable { - - private boolean isGecko = false; - private boolean isWebKit = false; - private boolean isPresto = false; - - private boolean isSafari = false; - private boolean isChrome = false; - private boolean isFirefox = false; - private boolean isOpera = false; - private boolean isIE = false; - - private boolean isWindows = false; - private boolean isMacOSX = false; - private boolean isLinux = false; - - private float browserEngineVersion = -1; - private int browserMajorVersion = -1; - private int browserMinorVersion = -1; - - /** - * Create an instance based on the given user agent. - * - * @param userAgent - * User agent as provided by the browser. - */ - public VBrowserDetails(String userAgent) { - userAgent = userAgent.toLowerCase(); - - // browser engine name - isGecko = userAgent.indexOf("gecko") != -1 - && userAgent.indexOf("webkit") == -1; - isWebKit = userAgent.indexOf("applewebkit") != -1; - isPresto = userAgent.indexOf(" presto/") != -1; - - // browser name - isChrome = userAgent.indexOf(" chrome/") != -1; - isSafari = !isChrome && userAgent.indexOf("safari") != -1; - isOpera = userAgent.indexOf("opera") != -1; - isIE = userAgent.indexOf("msie") != -1 && !isOpera - && (userAgent.indexOf("webtv") == -1); - isFirefox = userAgent.indexOf(" firefox/") != -1; - - // Rendering engine version - try { - if (isGecko) { - int rvPos = userAgent.indexOf("rv:"); - if (rvPos >= 0) { - String tmp = userAgent.substring(rvPos + 3); - tmp = tmp.replaceFirst("(\\.[0-9]+).+", "$1"); - browserEngineVersion = Float.parseFloat(tmp); - } - } else if (isWebKit) { - String tmp = userAgent - .substring(userAgent.indexOf("webkit/") + 7); - tmp = tmp.replaceFirst("([0-9]+)[^0-9].+", "$1"); - browserEngineVersion = Float.parseFloat(tmp); - } - } catch (Exception e) { - // Browser engine version parsing failed - System.err.println("Browser engine version parsing failed for: " - + userAgent); - } - - // Browser version - try { - if (isIE) { - String ieVersionString = userAgent.substring(userAgent - .indexOf("msie ") + 5); - ieVersionString = safeSubstring(ieVersionString, 0, - ieVersionString.indexOf(";")); - parseVersionString(ieVersionString); - } else if (isFirefox) { - int i = userAgent.indexOf(" firefox/") + 9; - parseVersionString(safeSubstring(userAgent, i, i + 5)); - } else if (isChrome) { - int i = userAgent.indexOf(" chrome/") + 8; - parseVersionString(safeSubstring(userAgent, i, i + 5)); - } else if (isSafari) { - int i = userAgent.indexOf(" version/") + 9; - parseVersionString(safeSubstring(userAgent, i, i + 5)); - } else if (isOpera) { - int i = userAgent.indexOf(" version/"); - if (i != -1) { - // Version present in Opera 10 and newer - i += 9; // " version/".length - } else { - i = userAgent.indexOf("opera/") + 6; - } - parseVersionString(safeSubstring(userAgent, i, i + 5)); - } - } catch (Exception e) { - // Browser version parsing failed - System.err.println("Browser version parsing failed for: " - + userAgent); - } - - // Operating system - if (userAgent.contains("windows ")) { - isWindows = true; - } else if (userAgent.contains("linux")) { - isLinux = true; - } else if (userAgent.contains("macintosh") - || userAgent.contains("mac osx") - || userAgent.contains("mac os x")) { - isMacOSX = true; - } - } - - private void parseVersionString(String versionString) { - int idx = versionString.indexOf('.'); - if (idx < 0) { - idx = versionString.length(); - } - browserMajorVersion = Integer.parseInt(safeSubstring(versionString, 0, - idx)); - - int idx2 = versionString.indexOf('.', idx + 1); - if (idx2 < 0) { - idx2 = versionString.length(); - } - try { - browserMinorVersion = Integer.parseInt(safeSubstring(versionString, - idx + 1, idx2).replaceAll("[^0-9].*", "")); - } catch (NumberFormatException e) { - // leave the minor version unmodified (-1 = unknown) - } - } - - private String safeSubstring(String string, int beginIndex, int endIndex) { - if (beginIndex < 0) { - beginIndex = 0; - } - if (endIndex < 0 || endIndex > string.length()) { - endIndex = string.length(); - } - return string.substring(beginIndex, endIndex); - } - - /** - * Tests if the browser is Firefox. - * - * @return true if it is Firefox, false otherwise - */ - public boolean isFirefox() { - return isFirefox; - } - - /** - * Tests if the browser is using the Gecko engine - * - * @return true if it is Gecko, false otherwise - */ - public boolean isGecko() { - return isGecko; - } - - /** - * Tests if the browser is using the WebKit engine - * - * @return true if it is WebKit, false otherwise - */ - public boolean isWebKit() { - return isWebKit; - } - - /** - * Tests if the browser is using the Presto engine - * - * @return true if it is Presto, false otherwise - */ - public boolean isPresto() { - return isPresto; - } - - /** - * Tests if the browser is Safari. - * - * @return true if it is Safari, false otherwise - */ - public boolean isSafari() { - return isSafari; - } - - /** - * Tests if the browser is Chrome. - * - * @return true if it is Chrome, false otherwise - */ - public boolean isChrome() { - return isChrome; - } - - /** - * Tests if the browser is Opera. - * - * @return true if it is Opera, false otherwise - */ - public boolean isOpera() { - return isOpera; - } - - /** - * Tests if the browser is Internet Explorer. - * - * @return true if it is Internet Explorer, false otherwise - */ - public boolean isIE() { - return isIE; - } - - /** - * Returns the version of the browser engine. For WebKit this is an integer - * e.g., 532.0. For gecko it is a float e.g., 1.8 or 1.9. - * - * @return The version of the browser engine - */ - public float getBrowserEngineVersion() { - return browserEngineVersion; - } - - /** - * Returns the browser major version e.g., 3 for Firefox 3.5, 4 for Chrome - * 4, 8 for Internet Explorer 8. - *

- * Note that Internet Explorer 8 and newer will return the document mode so - * IE8 rendering as IE7 will return 7. - *

- * - * @return The major version of the browser. - */ - public final int getBrowserMajorVersion() { - return browserMajorVersion; - } - - /** - * Returns the browser minor version e.g., 5 for Firefox 3.5. - * - * @see #getBrowserMajorVersion() - * - * @return The minor version of the browser, or -1 if not known/parsed. - */ - public final int getBrowserMinorVersion() { - return browserMinorVersion; - } - - /** - * Sets the version for IE based on the documentMode. This is used to return - * the correct the correct IE version when the version from the user agent - * string and the value of the documentMode property do not match. - * - * @param documentMode - * The current document mode - */ - public void setIEMode(int documentMode) { - browserMajorVersion = documentMode; - browserMinorVersion = 0; - } - - /** - * Tests if the browser is run on Windows. - * - * @return true if run on Windows, false otherwise - */ - public boolean isWindows() { - return isWindows; - } - - /** - * Tests if the browser is run on Mac OSX. - * - * @return true if run on Mac OSX, false otherwise - */ - public boolean isMacOSX() { - return isMacOSX; - } - - /** - * Tests if the browser is run on Linux. - * - * @return true if run on Linux, false otherwise - */ - public boolean isLinux() { - return isLinux; - } - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import java.io.Serializable; + +import com.vaadin.terminal.gwt.server.WebBrowser; + +/** + * Class that parses the user agent string from the browser and provides + * information about the browser. Used internally by {@link BrowserInfo} and + * {@link WebBrowser}. Should not be used directly. + * + * @author Vaadin Ltd. + * @version @VERSION@ + * @since 6.3 + */ +public class VBrowserDetails implements Serializable { + + private boolean isGecko = false; + private boolean isWebKit = false; + private boolean isPresto = false; + + private boolean isSafari = false; + private boolean isChrome = false; + private boolean isFirefox = false; + private boolean isOpera = false; + private boolean isIE = false; + + private boolean isWindows = false; + private boolean isMacOSX = false; + private boolean isLinux = false; + + private float browserEngineVersion = -1; + private int browserMajorVersion = -1; + private int browserMinorVersion = -1; + + /** + * Create an instance based on the given user agent. + * + * @param userAgent + * User agent as provided by the browser. + */ + public VBrowserDetails(String userAgent) { + userAgent = userAgent.toLowerCase(); + + // browser engine name + isGecko = userAgent.indexOf("gecko") != -1 + && userAgent.indexOf("webkit") == -1; + isWebKit = userAgent.indexOf("applewebkit") != -1; + isPresto = userAgent.indexOf(" presto/") != -1; + + // browser name + isChrome = userAgent.indexOf(" chrome/") != -1; + isSafari = !isChrome && userAgent.indexOf("safari") != -1; + isOpera = userAgent.indexOf("opera") != -1; + isIE = userAgent.indexOf("msie") != -1 && !isOpera + && (userAgent.indexOf("webtv") == -1); + isFirefox = userAgent.indexOf(" firefox/") != -1; + + // Rendering engine version + try { + if (isGecko) { + int rvPos = userAgent.indexOf("rv:"); + if (rvPos >= 0) { + String tmp = userAgent.substring(rvPos + 3); + tmp = tmp.replaceFirst("(\\.[0-9]+).+", "$1"); + browserEngineVersion = Float.parseFloat(tmp); + } + } else if (isWebKit) { + String tmp = userAgent + .substring(userAgent.indexOf("webkit/") + 7); + tmp = tmp.replaceFirst("([0-9]+)[^0-9].+", "$1"); + browserEngineVersion = Float.parseFloat(tmp); + } + } catch (Exception e) { + // Browser engine version parsing failed + System.err.println("Browser engine version parsing failed for: " + + userAgent); + } + + // Browser version + try { + if (isIE) { + String ieVersionString = userAgent.substring(userAgent + .indexOf("msie ") + 5); + ieVersionString = safeSubstring(ieVersionString, 0, + ieVersionString.indexOf(";")); + parseVersionString(ieVersionString); + } else if (isFirefox) { + int i = userAgent.indexOf(" firefox/") + 9; + parseVersionString(safeSubstring(userAgent, i, i + 5)); + } else if (isChrome) { + int i = userAgent.indexOf(" chrome/") + 8; + parseVersionString(safeSubstring(userAgent, i, i + 5)); + } else if (isSafari) { + int i = userAgent.indexOf(" version/") + 9; + parseVersionString(safeSubstring(userAgent, i, i + 5)); + } else if (isOpera) { + int i = userAgent.indexOf(" version/"); + if (i != -1) { + // Version present in Opera 10 and newer + i += 9; // " version/".length + } else { + i = userAgent.indexOf("opera/") + 6; + } + parseVersionString(safeSubstring(userAgent, i, i + 5)); + } + } catch (Exception e) { + // Browser version parsing failed + System.err.println("Browser version parsing failed for: " + + userAgent); + } + + // Operating system + if (userAgent.contains("windows ")) { + isWindows = true; + } else if (userAgent.contains("linux")) { + isLinux = true; + } else if (userAgent.contains("macintosh") + || userAgent.contains("mac osx") + || userAgent.contains("mac os x")) { + isMacOSX = true; + } + } + + private void parseVersionString(String versionString) { + int idx = versionString.indexOf('.'); + if (idx < 0) { + idx = versionString.length(); + } + browserMajorVersion = Integer.parseInt(safeSubstring(versionString, 0, + idx)); + + int idx2 = versionString.indexOf('.', idx + 1); + if (idx2 < 0) { + idx2 = versionString.length(); + } + try { + browserMinorVersion = Integer.parseInt(safeSubstring(versionString, + idx + 1, idx2).replaceAll("[^0-9].*", "")); + } catch (NumberFormatException e) { + // leave the minor version unmodified (-1 = unknown) + } + } + + private String safeSubstring(String string, int beginIndex, int endIndex) { + if (beginIndex < 0) { + beginIndex = 0; + } + if (endIndex < 0 || endIndex > string.length()) { + endIndex = string.length(); + } + return string.substring(beginIndex, endIndex); + } + + /** + * Tests if the browser is Firefox. + * + * @return true if it is Firefox, false otherwise + */ + public boolean isFirefox() { + return isFirefox; + } + + /** + * Tests if the browser is using the Gecko engine + * + * @return true if it is Gecko, false otherwise + */ + public boolean isGecko() { + return isGecko; + } + + /** + * Tests if the browser is using the WebKit engine + * + * @return true if it is WebKit, false otherwise + */ + public boolean isWebKit() { + return isWebKit; + } + + /** + * Tests if the browser is using the Presto engine + * + * @return true if it is Presto, false otherwise + */ + public boolean isPresto() { + return isPresto; + } + + /** + * Tests if the browser is Safari. + * + * @return true if it is Safari, false otherwise + */ + public boolean isSafari() { + return isSafari; + } + + /** + * Tests if the browser is Chrome. + * + * @return true if it is Chrome, false otherwise + */ + public boolean isChrome() { + return isChrome; + } + + /** + * Tests if the browser is Opera. + * + * @return true if it is Opera, false otherwise + */ + public boolean isOpera() { + return isOpera; + } + + /** + * Tests if the browser is Internet Explorer. + * + * @return true if it is Internet Explorer, false otherwise + */ + public boolean isIE() { + return isIE; + } + + /** + * Returns the version of the browser engine. For WebKit this is an integer + * e.g., 532.0. For gecko it is a float e.g., 1.8 or 1.9. + * + * @return The version of the browser engine + */ + public float getBrowserEngineVersion() { + return browserEngineVersion; + } + + /** + * Returns the browser major version e.g., 3 for Firefox 3.5, 4 for Chrome + * 4, 8 for Internet Explorer 8. + *

+ * Note that Internet Explorer 8 and newer will return the document mode so + * IE8 rendering as IE7 will return 7. + *

+ * + * @return The major version of the browser. + */ + public final int getBrowserMajorVersion() { + return browserMajorVersion; + } + + /** + * Returns the browser minor version e.g., 5 for Firefox 3.5. + * + * @see #getBrowserMajorVersion() + * + * @return The minor version of the browser, or -1 if not known/parsed. + */ + public final int getBrowserMinorVersion() { + return browserMinorVersion; + } + + /** + * Sets the version for IE based on the documentMode. This is used to return + * the correct the correct IE version when the version from the user agent + * string and the value of the documentMode property do not match. + * + * @param documentMode + * The current document mode + */ + public void setIEMode(int documentMode) { + browserMajorVersion = documentMode; + browserMinorVersion = 0; + } + + /** + * Tests if the browser is run on Windows. + * + * @return true if run on Windows, false otherwise + */ + public boolean isWindows() { + return isWindows; + } + + /** + * Tests if the browser is run on Mac OSX. + * + * @return true if run on Mac OSX, false otherwise + */ + public boolean isMacOSX() { + return isMacOSX; + } + + /** + * Tests if the browser is run on Linux. + * + * @return true if run on Linux, false otherwise + */ + public boolean isLinux() { + return isLinux; + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/VSchedulerImpl.java b/src/com/vaadin/terminal/gwt/client/VSchedulerImpl.java index 6bef0c409c..65d5d6a9a2 100644 --- a/src/com/vaadin/terminal/gwt/client/VSchedulerImpl.java +++ b/src/com/vaadin/terminal/gwt/client/VSchedulerImpl.java @@ -1,32 +1,32 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client; - -import com.google.gwt.core.client.impl.SchedulerImpl; - -public class VSchedulerImpl extends SchedulerImpl { - - /** - * Keeps track of if there are deferred commands that are being executed. 0 - * == no deferred commands currently in progress, > 0 otherwise. - */ - private int deferredCommandTrackers = 0; - - @Override - public void scheduleDeferred(ScheduledCommand cmd) { - deferredCommandTrackers++; - super.scheduleDeferred(cmd); - super.scheduleDeferred(new ScheduledCommand() { - - public void execute() { - deferredCommandTrackers--; - } - }); - } - - public boolean hasWorkQueued() { - boolean hasWorkQueued = (deferredCommandTrackers != 0); - return hasWorkQueued; - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import com.google.gwt.core.client.impl.SchedulerImpl; + +public class VSchedulerImpl extends SchedulerImpl { + + /** + * Keeps track of if there are deferred commands that are being executed. 0 + * == no deferred commands currently in progress, > 0 otherwise. + */ + private int deferredCommandTrackers = 0; + + @Override + public void scheduleDeferred(ScheduledCommand cmd) { + deferredCommandTrackers++; + super.scheduleDeferred(cmd); + super.scheduleDeferred(new ScheduledCommand() { + + public void execute() { + deferredCommandTrackers--; + } + }); + } + + public boolean hasWorkQueued() { + boolean hasWorkQueued = (deferredCommandTrackers != 0); + return hasWorkQueued; + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/CalendarEntry.java b/src/com/vaadin/terminal/gwt/client/ui/CalendarEntry.java index cf18c693c6..1577d60ab7 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/CalendarEntry.java +++ b/src/com/vaadin/terminal/gwt/client/ui/CalendarEntry.java @@ -1,128 +1,128 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.Date; - -import com.vaadin.terminal.gwt.client.DateTimeService; - -public class CalendarEntry { - private final String styleName; - private Date start; - private Date end; - private String title; - private String description; - private boolean notime; - - @SuppressWarnings("deprecation") - public CalendarEntry(String styleName, Date start, Date end, String title, - String description, boolean notime) { - this.styleName = styleName; - if (notime) { - Date d = new Date(start.getTime()); - d.setSeconds(0); - d.setMinutes(0); - this.start = d; - if (end != null) { - d = new Date(end.getTime()); - d.setSeconds(0); - d.setMinutes(0); - this.end = d; - } else { - end = start; - } - } else { - this.start = start; - this.end = end; - } - this.title = title; - this.description = description; - this.notime = notime; - } - - public CalendarEntry(String styleName, Date start, Date end, String title, - String description) { - this(styleName, start, end, title, description, false); - } - - public String getStyleName() { - return styleName; - } - - public Date getStart() { - return start; - } - - public void setStart(Date start) { - this.start = start; - } - - public Date getEnd() { - return end; - } - - public void setEnd(Date end) { - this.end = end; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public boolean isNotime() { - return notime; - } - - public void setNotime(boolean notime) { - this.notime = notime; - } - - @SuppressWarnings("deprecation") - public String getStringForDate(Date d) { - // TODO format from DateTimeService - String s = ""; - if (!notime) { - if (!DateTimeService.isSameDay(d, start)) { - s += (start.getYear() + 1900) + "." + (start.getMonth() + 1) - + "." + start.getDate() + " "; - } - int i = start.getHours(); - s += (i < 10 ? "0" : "") + i; - s += ":"; - i = start.getMinutes(); - s += (i < 10 ? "0" : "") + i; - if (!start.equals(end)) { - s += " - "; - if (!DateTimeService.isSameDay(start, end)) { - s += (end.getYear() + 1900) + "." + (end.getMonth() + 1) - + "." + end.getDate() + " "; - } - i = end.getHours(); - s += (i < 10 ? "0" : "") + i; - s += ":"; - i = end.getMinutes(); - s += (i < 10 ? "0" : "") + i; - } - s += " "; - } - if (title != null) { - s += title; - } - return s; - } - +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import java.util.Date; + +import com.vaadin.terminal.gwt.client.DateTimeService; + +public class CalendarEntry { + private final String styleName; + private Date start; + private Date end; + private String title; + private String description; + private boolean notime; + + @SuppressWarnings("deprecation") + public CalendarEntry(String styleName, Date start, Date end, String title, + String description, boolean notime) { + this.styleName = styleName; + if (notime) { + Date d = new Date(start.getTime()); + d.setSeconds(0); + d.setMinutes(0); + this.start = d; + if (end != null) { + d = new Date(end.getTime()); + d.setSeconds(0); + d.setMinutes(0); + this.end = d; + } else { + end = start; + } + } else { + this.start = start; + this.end = end; + } + this.title = title; + this.description = description; + this.notime = notime; + } + + public CalendarEntry(String styleName, Date start, Date end, String title, + String description) { + this(styleName, start, end, title, description, false); + } + + public String getStyleName() { + return styleName; + } + + public Date getStart() { + return start; + } + + public void setStart(Date start) { + this.start = start; + } + + public Date getEnd() { + return end; + } + + public void setEnd(Date end) { + this.end = end; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public boolean isNotime() { + return notime; + } + + public void setNotime(boolean notime) { + this.notime = notime; + } + + @SuppressWarnings("deprecation") + public String getStringForDate(Date d) { + // TODO format from DateTimeService + String s = ""; + if (!notime) { + if (!DateTimeService.isSameDay(d, start)) { + s += (start.getYear() + 1900) + "." + (start.getMonth() + 1) + + "." + start.getDate() + " "; + } + int i = start.getHours(); + s += (i < 10 ? "0" : "") + i; + s += ":"; + i = start.getMinutes(); + s += (i < 10 ? "0" : "") + i; + if (!start.equals(end)) { + s += " - "; + if (!DateTimeService.isSameDay(start, end)) { + s += (end.getYear() + 1900) + "." + (end.getMonth() + 1) + + "." + end.getDate() + " "; + } + i = end.getHours(); + s += (i < 10 ? "0" : "") + i; + s += ":"; + i = end.getMinutes(); + s += (i < 10 ? "0" : "") + i; + } + s += " "; + } + if (title != null) { + s += title; + } + return s; + } + } \ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/FocusableFlowPanel.java b/src/com/vaadin/terminal/gwt/client/ui/FocusableFlowPanel.java index 0ca97d2bf8..831add049b 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/FocusableFlowPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/FocusableFlowPanel.java @@ -1,100 +1,100 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.FocusEvent; -import com.google.gwt.event.dom.client.FocusHandler; -import com.google.gwt.event.dom.client.HasBlurHandlers; -import com.google.gwt.event.dom.client.HasFocusHandlers; -import com.google.gwt.event.dom.client.HasKeyDownHandlers; -import com.google.gwt.event.dom.client.HasKeyPressHandlers; -import com.google.gwt.event.dom.client.KeyDownEvent; -import com.google.gwt.event.dom.client.KeyDownHandler; -import com.google.gwt.event.dom.client.KeyPressEvent; -import com.google.gwt.event.dom.client.KeyPressHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.impl.FocusImpl; -import com.vaadin.terminal.gwt.client.Focusable; - -public class FocusableFlowPanel extends FlowPanel implements HasFocusHandlers, - HasBlurHandlers, HasKeyDownHandlers, HasKeyPressHandlers, Focusable { - - /** - * Constructor - */ - public FocusableFlowPanel() { - // make focusable, as we don't need access key magic we don't need to - // use FocusImpl.createFocusable - getElement().setTabIndex(0); - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com. - * google.gwt.event.dom.client.FocusHandler) - */ - public HandlerRegistration addFocusHandler(FocusHandler handler) { - return addDomHandler(handler, FocusEvent.getType()); - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.HasBlurHandlers#addBlurHandler(com.google - * .gwt.event.dom.client.BlurHandler) - */ - public HandlerRegistration addBlurHandler(BlurHandler handler) { - return addDomHandler(handler, BlurEvent.getType()); - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.HasKeyDownHandlers#addKeyDownHandler( - * com.google.gwt.event.dom.client.KeyDownHandler) - */ - public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) { - return addDomHandler(handler, KeyDownEvent.getType()); - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.HasKeyPressHandlers#addKeyPressHandler - * (com.google.gwt.event.dom.client.KeyPressHandler) - */ - public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) { - return addDomHandler(handler, KeyPressEvent.getType()); - } - - /** - * Sets/Removes the keyboard focus to the panel. - * - * @param focus - * If set to true then the focus is moved to the panel, if set to - * false the focus is removed - */ - public void setFocus(boolean focus) { - if (focus) { - FocusImpl.getFocusImplForPanel().focus(getElement()); - } else { - FocusImpl.getFocusImplForPanel().blur(getElement()); - } - } - - /** - * Focus the panel - */ - public void focus() { - setFocus(true); - } +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import com.google.gwt.event.dom.client.BlurEvent; +import com.google.gwt.event.dom.client.BlurHandler; +import com.google.gwt.event.dom.client.FocusEvent; +import com.google.gwt.event.dom.client.FocusHandler; +import com.google.gwt.event.dom.client.HasBlurHandlers; +import com.google.gwt.event.dom.client.HasFocusHandlers; +import com.google.gwt.event.dom.client.HasKeyDownHandlers; +import com.google.gwt.event.dom.client.HasKeyPressHandlers; +import com.google.gwt.event.dom.client.KeyDownEvent; +import com.google.gwt.event.dom.client.KeyDownHandler; +import com.google.gwt.event.dom.client.KeyPressEvent; +import com.google.gwt.event.dom.client.KeyPressHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.impl.FocusImpl; +import com.vaadin.terminal.gwt.client.Focusable; + +public class FocusableFlowPanel extends FlowPanel implements HasFocusHandlers, + HasBlurHandlers, HasKeyDownHandlers, HasKeyPressHandlers, Focusable { + + /** + * Constructor + */ + public FocusableFlowPanel() { + // make focusable, as we don't need access key magic we don't need to + // use FocusImpl.createFocusable + getElement().setTabIndex(0); + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com. + * google.gwt.event.dom.client.FocusHandler) + */ + public HandlerRegistration addFocusHandler(FocusHandler handler) { + return addDomHandler(handler, FocusEvent.getType()); + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.HasBlurHandlers#addBlurHandler(com.google + * .gwt.event.dom.client.BlurHandler) + */ + public HandlerRegistration addBlurHandler(BlurHandler handler) { + return addDomHandler(handler, BlurEvent.getType()); + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.HasKeyDownHandlers#addKeyDownHandler( + * com.google.gwt.event.dom.client.KeyDownHandler) + */ + public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) { + return addDomHandler(handler, KeyDownEvent.getType()); + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.HasKeyPressHandlers#addKeyPressHandler + * (com.google.gwt.event.dom.client.KeyPressHandler) + */ + public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) { + return addDomHandler(handler, KeyPressEvent.getType()); + } + + /** + * Sets/Removes the keyboard focus to the panel. + * + * @param focus + * If set to true then the focus is moved to the panel, if set to + * false the focus is removed + */ + public void setFocus(boolean focus) { + if (focus) { + FocusImpl.getFocusImplForPanel().focus(getElement()); + } else { + FocusImpl.getFocusImplForPanel().blur(getElement()); + } + } + + /** + * Focus the panel + */ + public void focus() { + setFocus(true); + } } \ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/TreeImages.java b/src/com/vaadin/terminal/gwt/client/ui/TreeImages.java index 8a153da98c..37f8889463 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/TreeImages.java +++ b/src/com/vaadin/terminal/gwt/client/ui/TreeImages.java @@ -1,29 +1,29 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.user.client.ui.AbstractImagePrototype; - -public interface TreeImages extends com.google.gwt.user.client.ui.TreeImages { - - /** - * An image indicating an open branch. - * - * @return a prototype of this image - * @gwt.resource com/vaadin/terminal/gwt/public/default/tree/img/expanded - * .png - */ - AbstractImagePrototype treeOpen(); - - /** - * An image indicating a closed branch. - * - * @return a prototype of this image - * @gwt.resource com/vaadin/terminal/gwt/public/default/tree/img/collapsed - * .png - */ - AbstractImagePrototype treeClosed(); - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import com.google.gwt.user.client.ui.AbstractImagePrototype; + +public interface TreeImages extends com.google.gwt.user.client.ui.TreeImages { + + /** + * An image indicating an open branch. + * + * @return a prototype of this image + * @gwt.resource com/vaadin/terminal/gwt/public/default/tree/img/expanded + * .png + */ + AbstractImagePrototype treeOpen(); + + /** + * An image indicating a closed branch. + * + * @return a prototype of this image + * @gwt.resource com/vaadin/terminal/gwt/public/default/tree/img/collapsed + * .png + */ + AbstractImagePrototype treeClosed(); + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java index fb5070d9a2..e35bd93f67 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java @@ -1,1787 +1,1792 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.Date; -import java.util.Iterator; - -import com.google.gwt.dom.client.Node; -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.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.DomEvent; -import com.google.gwt.event.dom.client.FocusEvent; -import com.google.gwt.event.dom.client.FocusHandler; -import com.google.gwt.event.dom.client.KeyCodes; -import com.google.gwt.event.dom.client.KeyDownEvent; -import com.google.gwt.event.dom.client.KeyDownHandler; -import com.google.gwt.event.dom.client.KeyPressEvent; -import com.google.gwt.event.dom.client.KeyPressHandler; -import com.google.gwt.event.dom.client.MouseDownEvent; -import com.google.gwt.event.dom.client.MouseDownHandler; -import com.google.gwt.event.dom.client.MouseOutEvent; -import com.google.gwt.event.dom.client.MouseOutHandler; -import com.google.gwt.event.dom.client.MouseUpEvent; -import com.google.gwt.event.dom.client.MouseUpHandler; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Timer; -import com.google.gwt.user.client.ui.Button; -import com.google.gwt.user.client.ui.FlexTable; -import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.InlineHTML; -import com.google.gwt.user.client.ui.ListBox; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.DateTimeService; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VConsole; - -@SuppressWarnings("deprecation") -public class VCalendarPanel extends FocusableFlexTable implements - KeyDownHandler, KeyPressHandler, MouseOutHandler, MouseDownHandler, - MouseUpHandler, BlurHandler, FocusHandler, SubPartAware { - - public interface SubmitListener { - - /** - * Called when calendar user triggers a submitting operation in calendar - * panel. Eg. clicking on day or hitting enter. - */ - void onSubmit(); - - /** - * On eg. ESC key. - */ - void onCancel(); - } - - /** - * Blur listener that listens to blur event from the panel - */ - public interface FocusOutListener { - /** - * @return true if the calendar panel is not used after focus moves out - */ - boolean onFocusOut(DomEvent event); - } - - /** - * FocusChangeListener is notified when the panel changes its _focused_ - * value. - */ - public interface FocusChangeListener { - void focusChanged(Date focusedDate); - } - - /** - * Dispatches an event when the panel when time is changed - */ - public interface TimeChangeListener { - - void changed(int hour, int min, int sec, int msec); - } - - /** - * Represents a Date button in the calendar - */ - private class VEventButton extends Button { - public VEventButton() { - addMouseDownHandler(VCalendarPanel.this); - addMouseOutHandler(VCalendarPanel.this); - addMouseUpHandler(VCalendarPanel.this); - } - } - - private static final String CN_FOCUSED = "focused"; - - private static final String CN_TODAY = "today"; - - private static final String CN_SELECTED = "selected"; - - private static final String CN_OFFMONTH = "offmonth"; - - /** - * Represents a click handler for when a user selects a value by using the - * mouse - */ - private ClickHandler dayClickHandler = new ClickHandler() { - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt - * .event.dom.client.ClickEvent) - */ - public void onClick(ClickEvent event) { - Day day = (Day) event.getSource(); - focusDay(day.getDate()); - selectFocused(); - onSubmit(); - } - }; - - private VEventButton prevYear; - - private VEventButton nextYear; - - private VEventButton prevMonth; - - private VEventButton nextMonth; - - private VTime time; - - private FlexTable days = new FlexTable(); - - private int resolution = VDateField.RESOLUTION_YEAR; - - private int focusedRow; - - private Timer mouseTimer; - - private Date value; - - private boolean enabled = true; - - private boolean readonly = false; - - private DateTimeService dateTimeService; - - private boolean showISOWeekNumbers; - - private Date displayedMonth; - - private Date focusedDate; - - private Day selectedDay; - - private Day focusedDay; - - private FocusOutListener focusOutListener; - - private SubmitListener submitListener; - - private FocusChangeListener focusChangeListener; - - private TimeChangeListener timeChangeListener; - - private boolean hasFocus = false; - - public VCalendarPanel() { - - setStyleName(VDateField.CLASSNAME + "-calendarpanel"); - - /* - * Firefox auto-repeat works correctly only if we use a key press - * handler, other browsers handle it correctly when using a key down - * handler - */ - if (BrowserInfo.get().isGecko()) { - addKeyPressHandler(this); - } else { - addKeyDownHandler(this); - } - addFocusHandler(this); - addBlurHandler(this); - - } - - /** - * Sets the focus to given date in the current view. Used when moving in the - * calendar with the keyboard. - * - * @param date - * A Date representing the day of month to be focused. Must be - * one of the days currently visible. - */ - private void focusDay(Date date) { - // Only used when calender body is present - if (resolution > VDateField.RESOLUTION_MONTH) { - if (focusedDay != null) { - focusedDay.removeStyleDependentName(CN_FOCUSED); - } - - if (date != null && focusedDate != null) { - focusedDate.setTime(date.getTime()); - int rowCount = days.getRowCount(); - for (int i = 0; i < rowCount; i++) { - int cellCount = days.getCellCount(i); - for (int j = 0; j < cellCount; j++) { - Widget widget = days.getWidget(i, j); - if (widget != null && widget instanceof Day) { - Day curday = (Day) widget; - if (curday.getDate().equals(date)) { - curday.addStyleDependentName(CN_FOCUSED); - focusedDay = curday; - focusedRow = i; - return; - } - } - } - } - } - } - } - - /** - * Sets the selection highlight to a given day in the current view - * - * @param date - * A Date representing the day of month to be selected. Must be - * one of the days currently visible. - * - */ - private void selectDate(Date date) { - if (selectedDay != null) { - selectedDay.removeStyleDependentName(CN_SELECTED); - } - - int rowCount = days.getRowCount(); - for (int i = 0; i < rowCount; i++) { - int cellCount = days.getCellCount(i); - for (int j = 0; j < cellCount; j++) { - Widget widget = days.getWidget(i, j); - if (widget != null && widget instanceof Day) { - Day curday = (Day) widget; - if (curday.getDate().equals(date)) { - curday.addStyleDependentName(CN_SELECTED); - selectedDay = curday; - return; - } - } - } - } - } - - /** - * Updates year, month, day from focusedDate to value - */ - private void selectFocused() { - if (focusedDate != null) { - if (value == null) { - // No previously selected value (set to null on server side). - // Create a new date using current date and time - value = new Date(); - } - /* - * #5594 set Date (day) to 1 in order to prevent any kind of - * wrapping of months when later setting the month. (e.g. 31 -> - * month with 30 days -> wraps to the 1st of the following month, - * e.g. 31st of May -> 31st of April = 1st of May) - */ - value.setDate(1); - if (value.getYear() != focusedDate.getYear()) { - value.setYear(focusedDate.getYear()); - } - if (value.getMonth() != focusedDate.getMonth()) { - value.setMonth(focusedDate.getMonth()); - } - if (value.getDate() != focusedDate.getDate()) { - } - // We always need to set the date, even if it hasn't changed, since - // it was forced to 1 above. - value.setDate(focusedDate.getDate()); - - selectDate(focusedDate); - } else { - VConsole.log("Trying to select a the focused date which is NULL!"); - } - } - - protected boolean onValueChange() { - return false; - } - - public int getResolution() { - return resolution; - } - - public void setResolution(int resolution) { - this.resolution = resolution; - if (time != null) { - time.removeFromParent(); - time = null; - } - } - - private boolean isReadonly() { - return readonly; - } - - private boolean isEnabled() { - return enabled; - } - - private void clearCalendarBody(boolean remove) { - if (!remove) { - // Leave the cells in place but clear their contents - - // This has the side effect of ensuring that the calendar always - // contain 7 rows. - for (int row = 1; row < 7; row++) { - for (int col = 0; col < 8; col++) { - days.setHTML(row, col, " "); - } - } - } else if (getRowCount() > 1) { - removeRow(1); - days.clear(); - } - } - - /** - * Builds the top buttons and current month and year header. - * - * @param needsMonth - * Should the month buttons be visible? - */ - private void buildCalendarHeader(boolean needsMonth) { - - getRowFormatter().addStyleName(0, - VDateField.CLASSNAME + "-calendarpanel-header"); - - if (prevMonth == null && needsMonth) { - prevMonth = new VEventButton(); - prevMonth.setHTML("‹"); - prevMonth.setStyleName("v-button-prevmonth"); - prevMonth.setTabIndex(-1); - nextMonth = new VEventButton(); - nextMonth.setHTML("›"); - nextMonth.setStyleName("v-button-nextmonth"); - nextMonth.setTabIndex(-1); - getFlexCellFormatter().setStyleName(0, 3, - VDateField.CLASSNAME + "-calendarpanel-nextmonth"); - getFlexCellFormatter().setStyleName(0, 1, - VDateField.CLASSNAME + "-calendarpanel-prevmonth"); - - setWidget(0, 3, nextMonth); - setWidget(0, 1, prevMonth); - } else if (prevMonth != null && !needsMonth) { - // Remove month traverse buttons - remove(prevMonth); - remove(nextMonth); - prevMonth = null; - nextMonth = null; - } - - if (prevYear == null) { - prevYear = new VEventButton(); - prevYear.setHTML("«"); - prevYear.setStyleName("v-button-prevyear"); - prevYear.setTabIndex(-1); - nextYear = new VEventButton(); - nextYear.setHTML("»"); - nextYear.setStyleName("v-button-nextyear"); - nextYear.setTabIndex(-1); - setWidget(0, 0, prevYear); - setWidget(0, 4, nextYear); - getFlexCellFormatter().setStyleName(0, 0, - VDateField.CLASSNAME + "-calendarpanel-prevyear"); - getFlexCellFormatter().setStyleName(0, 4, - VDateField.CLASSNAME + "-calendarpanel-nextyear"); - } - - final String monthName = needsMonth ? getDateTimeService().getMonth( - focusedDate.getMonth()) : ""; - final int year = focusedDate.getYear() + 1900; - getFlexCellFormatter().setStyleName(0, 2, - VDateField.CLASSNAME + "-calendarpanel-month"); - setHTML(0, 2, "" + monthName + " " + year - + ""); - } - - private DateTimeService getDateTimeService() { - return dateTimeService; - } - - public void setDateTimeService(DateTimeService dateTimeService) { - this.dateTimeService = dateTimeService; - } - - /** - * Returns whether ISO 8601 week numbers should be shown in the value - * selector or not. ISO 8601 defines that a week always starts with a Monday - * so the week numbers are only shown if this is the case. - * - * @return true if week number should be shown, false otherwise - */ - public boolean isShowISOWeekNumbers() { - return showISOWeekNumbers; - } - - public void setShowISOWeekNumbers(boolean showISOWeekNumbers) { - this.showISOWeekNumbers = showISOWeekNumbers; - } - - /** - * Builds the day and time selectors of the calendar. - */ - private void buildCalendarBody() { - - final int weekColumn = 0; - final int firstWeekdayColumn = 1; - final int headerRow = 0; - - setWidget(1, 0, days); - setCellPadding(0); - setCellSpacing(0); - getFlexCellFormatter().setColSpan(1, 0, 5); - getFlexCellFormatter().setStyleName(1, 0, - VDateField.CLASSNAME + "-calendarpanel-body"); - - days.getFlexCellFormatter().setStyleName(headerRow, weekColumn, - "v-week"); - days.setHTML(headerRow, weekColumn, ""); - // Hide the week column if week numbers are not to be displayed. - days.getFlexCellFormatter().setVisible(headerRow, weekColumn, - isShowISOWeekNumbers()); - - days.getRowFormatter().setStyleName(headerRow, - VDateField.CLASSNAME + "-calendarpanel-weekdays"); - - if (isShowISOWeekNumbers()) { - days.getFlexCellFormatter().setStyleName(headerRow, weekColumn, - "v-first"); - days.getFlexCellFormatter().setStyleName(headerRow, - firstWeekdayColumn, ""); - days.getRowFormatter().addStyleName(headerRow, - VDateField.CLASSNAME + "-calendarpanel-weeknumbers"); - } else { - days.getFlexCellFormatter().setStyleName(headerRow, weekColumn, ""); - days.getFlexCellFormatter().setStyleName(headerRow, - firstWeekdayColumn, "v-first"); - } - - days.getFlexCellFormatter().setStyleName(headerRow, - firstWeekdayColumn + 6, "v-last"); - - // Print weekday names - final int firstDay = getDateTimeService().getFirstDayOfWeek(); - for (int i = 0; i < 7; i++) { - int day = i + firstDay; - if (day > 6) { - day = 0; - } - if (getResolution() > VDateField.RESOLUTION_MONTH) { - days.setHTML(headerRow, firstWeekdayColumn + i, "" - + getDateTimeService().getShortDay(day) + ""); - } else { - days.setHTML(headerRow, firstWeekdayColumn + i, ""); - } - } - - // today must have zeroed hours, minutes, seconds, and milliseconds - final Date tmp = new Date(); - final Date today = new Date(tmp.getYear(), tmp.getMonth(), - tmp.getDate()); - - final int startWeekDay = getDateTimeService().getStartWeekDay( - focusedDate); - final Date curr = (Date) focusedDate.clone(); - // Start from the first day of the week that at least partially belongs - // to the current month - curr.setDate(-startWeekDay); - - // No month has more than 6 weeks so 6 is a safe maximum for rows. - for (int weekOfMonth = 1; weekOfMonth < 7; weekOfMonth++) { - for (int dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) { - - // Actually write the day of month - Day day = new Day((Date) curr.clone()); - - if (curr.equals(value)) { - day.addStyleDependentName(CN_SELECTED); - selectedDay = day; - } - if (curr.equals(today)) { - day.addStyleDependentName(CN_TODAY); - } - if (curr.equals(focusedDate)) { - focusedDay = day; - focusedRow = weekOfMonth; - if (hasFocus) { - day.addStyleDependentName(CN_FOCUSED); - } - } - if (curr.getMonth() != focusedDate.getMonth()) { - day.addStyleDependentName(CN_OFFMONTH); - } - - days.setWidget(weekOfMonth, firstWeekdayColumn + dayOfWeek, day); - - // ISO week numbers if requested - days.getCellFormatter().setVisible(weekOfMonth, weekColumn, - isShowISOWeekNumbers()); - if (isShowISOWeekNumbers()) { - final String baseCssClass = VDateField.CLASSNAME - + "-calendarpanel-weeknumber"; - String weekCssClass = baseCssClass; - - int weekNumber = DateTimeService.getISOWeekNumber(curr); - - days.setHTML(weekOfMonth, 0, "" + weekNumber - + ""); - } - curr.setDate(curr.getDate() + 1); - } - } - } - - /** - * Do we need the time selector - * - * @return True if it is required - */ - private boolean isTimeSelectorNeeded() { - return getResolution() > VDateField.RESOLUTION_DAY; - } - - /** - * Updates the calendar and text field with the selected dates. - */ - public void renderCalendar() { - if (focusedDate == null) { - focusedDate = new Date(); - } - - if (getResolution() <= VDateField.RESOLUTION_MONTH - && focusChangeListener != null) { - focusChangeListener.focusChanged(new Date(focusedDate.getTime())); - } - - final boolean needsMonth = getResolution() > VDateField.RESOLUTION_YEAR; - boolean needsBody = getResolution() >= VDateField.RESOLUTION_DAY; - buildCalendarHeader(needsMonth); - clearCalendarBody(!needsBody); - if (needsBody) { - buildCalendarBody(); - } - - if (isTimeSelectorNeeded() && time == null) { - time = new VTime(); - setWidget(2, 0, time); - getFlexCellFormatter().setColSpan(2, 0, 5); - getFlexCellFormatter().setStyleName(2, 0, - VDateField.CLASSNAME + "-calendarpanel-time"); - } else if (isTimeSelectorNeeded()) { - time.updateTimes(); - } else if (time != null) { - remove(time); - } - - } - - /** - * Selects the next month - */ - private void focusNextMonth() { - - int currentMonth = focusedDate.getMonth(); - focusedDate.setMonth(currentMonth + 1); - int requestedMonth = (currentMonth + 1) % 12; - - /* - * If the selected value was e.g. 31.3 the new value would be 31.4 but - * this value is invalid so the new value will be 1.5. This is taken - * care of by decreasing the value until we have the correct month. - */ - while (focusedDate.getMonth() != requestedMonth) { - focusedDate.setDate(focusedDate.getDate() - 1); - } - displayedMonth.setMonth(displayedMonth.getMonth() + 1); - - renderCalendar(); - } - - /** - * Selects the previous month - */ - private void focusPreviousMonth() { - int currentMonth = focusedDate.getMonth(); - focusedDate.setMonth(currentMonth - 1); - - /* - * If the selected value was e.g. 31.12 the new value would be 31.11 but - * this value is invalid so the new value will be 1.12. This is taken - * care of by decreasing the value until we have the correct month. - */ - while (focusedDate.getMonth() == currentMonth) { - focusedDate.setDate(focusedDate.getDate() - 1); - } - displayedMonth.setMonth(displayedMonth.getMonth() - 1); - - renderCalendar(); - } - - /** - * Selects the previous year - */ - private void focusPreviousYear(int years) { - focusedDate.setYear(focusedDate.getYear() - years); - displayedMonth.setYear(displayedMonth.getYear() - years); - renderCalendar(); - } - - /** - * Selects the next year - */ - private void focusNextYear(int years) { - focusedDate.setYear(focusedDate.getYear() + years); - displayedMonth.setYear(displayedMonth.getYear() + years); - renderCalendar(); - } - - /** - * Handles a user click on the component - * - * @param sender - * The component that was clicked - * @param updateVariable - * Should the value field be updated - * - */ - private void processClickEvent(Widget sender) { - if (!isEnabled() || isReadonly()) { - return; - } - if (sender == prevYear) { - focusPreviousYear(1); - } else if (sender == nextYear) { - focusNextYear(1); - } else if (sender == prevMonth) { - focusPreviousMonth(); - } else if (sender == nextMonth) { - focusNextMonth(); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.KeyDownHandler#onKeyDown(com.google.gwt - * .event.dom.client.KeyDownEvent) - */ - public void onKeyDown(KeyDownEvent event) { - handleKeyPress(event); - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.KeyPressHandler#onKeyPress(com.google - * .gwt.event.dom.client.KeyPressEvent) - */ - public void onKeyPress(KeyPressEvent event) { - handleKeyPress(event); - } - - /** - * Handles the keypress from both the onKeyPress event and the onKeyDown - * event - * - * @param event - * The keydown/keypress event - */ - private void handleKeyPress(DomEvent event) { - if (time != null - && time.getElement().isOrHasChild( - (Node) event.getNativeEvent().getEventTarget().cast())) { - int nativeKeyCode = event.getNativeEvent().getKeyCode(); - if (nativeKeyCode == getSelectKey()) { - onSubmit(); // submit happens if enter key hit down on listboxes - event.preventDefault(); - event.stopPropagation(); - } - return; - } - - // Check tabs - int keycode = event.getNativeEvent().getKeyCode(); - if (keycode == KeyCodes.KEY_TAB && event.getNativeEvent().getShiftKey()) { - if (onTabOut(event)) { - return; - } - } - - // Handle the navigation - if (handleNavigation(keycode, event.getNativeEvent().getCtrlKey() - || event.getNativeEvent().getMetaKey(), event.getNativeEvent() - .getShiftKey())) { - event.preventDefault(); - } - - } - - /** - * Notifies submit-listeners of a submit event - */ - private void onSubmit() { - if (getSubmitListener() != null) { - getSubmitListener().onSubmit(); - } - } - - /** - * Notifies submit-listeners of a cancel event - */ - private void onCancel() { - if (getSubmitListener() != null) { - getSubmitListener().onCancel(); - } - } - - /** - * Handles the keyboard navigation when the resolution is set to years. - * - * @param keycode - * The keycode to process - * @param ctrl - * Is ctrl pressed? - * @param shift - * is shift pressed - * @return Returns true if the keycode was processed, else false - */ - protected boolean handleNavigationYearMode(int keycode, boolean ctrl, - boolean shift) { - - // Ctrl and Shift selection not supported - if (ctrl || shift) { - return false; - } - - else if (keycode == getPreviousKey()) { - focusNextYear(10); // Add 10 years - return true; - } - - else if (keycode == getForwardKey()) { - focusNextYear(1); // Add 1 year - return true; - } - - else if (keycode == getNextKey()) { - focusPreviousYear(10); // Subtract 10 years - return true; - } - - else if (keycode == getBackwardKey()) { - focusPreviousYear(1); // Subtract 1 year - return true; - - } else if (keycode == getSelectKey()) { - value = (Date) focusedDate.clone(); - onSubmit(); - return true; - - } else if (keycode == getResetKey()) { - // Restore showing value the selected value - focusedDate.setTime(value.getTime()); - renderCalendar(); - return true; - - } else if (keycode == getCloseKey()) { - // TODO fire listener, on users responsibility?? - - return true; - } - return false; - } - - /** - * Handle the keyboard navigation when the resolution is set to MONTH - * - * @param keycode - * The keycode to handle - * @param ctrl - * Was the ctrl key pressed? - * @param shift - * Was the shift key pressed? - * @return - */ - protected boolean handleNavigationMonthMode(int keycode, boolean ctrl, - boolean shift) { - - // Ctrl selection not supported - if (ctrl) { - return false; - - } else if (keycode == getPreviousKey()) { - focusNextYear(1); // Add 1 year - return true; - - } else if (keycode == getForwardKey()) { - focusNextMonth(); // Add 1 month - return true; - - } else if (keycode == getNextKey()) { - focusPreviousYear(1); // Subtract 1 year - return true; - - } else if (keycode == getBackwardKey()) { - focusPreviousMonth(); // Subtract 1 month - return true; - - } else if (keycode == getSelectKey()) { - value = (Date) focusedDate.clone(); - onSubmit(); - return true; - - } else if (keycode == getResetKey()) { - // Restore showing value the selected value - focusedDate.setTime(value.getTime()); - renderCalendar(); - return true; - - } else if (keycode == getCloseKey() || keycode == KeyCodes.KEY_TAB) { - - // TODO fire close event - - return true; - } - - return false; - } - - /** - * Handle keyboard navigation what the resolution is set to DAY - * - * @param keycode - * The keycode to handle - * @param ctrl - * Was the ctrl key pressed? - * @param shift - * Was the shift key pressed? - * @return Return true if the key press was handled by the method, else - * return false. - */ - protected boolean handleNavigationDayMode(int keycode, boolean ctrl, - boolean shift) { - - // Ctrl key is not in use - if (ctrl) { - return false; - } - - /* - * Jumps to the next day. - */ - if (keycode == getForwardKey() && !shift) { - // Calculate new showing value - - Date newCurrentDate = (Date) focusedDate.clone(); - - newCurrentDate.setDate(newCurrentDate.getDate() + 1); - - if (newCurrentDate.getMonth() == focusedDate.getMonth()) { - // Month did not change, only move the selection - focusDay(newCurrentDate); - } else { - // If the month changed we need to re-render the calendar - focusedDate.setDate(focusedDate.getDate() + 1); - renderCalendar(); - } - - return true; - - /* - * Jumps to the previous day - */ - } else if (keycode == getBackwardKey() && !shift) { - // Calculate new showing value - Date newCurrentDate = (Date) focusedDate.clone(); - newCurrentDate.setDate(newCurrentDate.getDate() - 1); - - if (newCurrentDate.getMonth() == focusedDate.getMonth()) { - // Month did not change, only move the selection - focusDay(newCurrentDate); - } else { - // If the month changed we need to re-render the calendar - focusedDate.setDate(focusedDate.getDate() - 1); - renderCalendar(); - } - - return true; - - /* - * Jumps one week back in the calendar - */ - } else if (keycode == getPreviousKey() && !shift) { - // Calculate new showing value - Date newCurrentDate = (Date) focusedDate.clone(); - newCurrentDate.setDate(newCurrentDate.getDate() - 7); - - if (newCurrentDate.getMonth() == focusedDate.getMonth() - && focusedRow > 1) { - // Month did not change, only move the selection - focusDay(newCurrentDate); - } else { - // If the month changed we need to re-render the calendar - focusedDate = newCurrentDate; - renderCalendar(); - } - - return true; - - /* - * Jumps one week forward in the calendar - */ - } else if (keycode == getNextKey() && !ctrl && !shift) { - // Calculate new showing value - Date newCurrentDate = (Date) focusedDate.clone(); - newCurrentDate.setDate(newCurrentDate.getDate() + 7); - - if (newCurrentDate.getMonth() == focusedDate.getMonth()) { - // Month did not change, only move the selection - focusDay(newCurrentDate); - } else { - // If the month changed we need to re-render the calendar - focusedDate = newCurrentDate; - renderCalendar(); - - } - - return true; - - /* - * Selects the value that is chosen - */ - } else if (keycode == getSelectKey() && !shift) { - selectFocused(); - onSubmit(); // submit - return true; - } else if (keycode == getCloseKey()) { - onCancel(); - // TODO close event - - return true; - - /* - * Jumps to the next month - */ - } else if (shift && keycode == getForwardKey()) { - focusNextMonth(); - return true; - - /* - * Jumps to the previous month - */ - } else if (shift && keycode == getBackwardKey()) { - focusPreviousMonth(); - return true; - - /* - * Jumps to the next year - */ - } else if (shift && keycode == getPreviousKey()) { - focusNextYear(1); - return true; - - /* - * Jumps to the previous year - */ - } else if (shift && keycode == getNextKey()) { - focusPreviousYear(1); - return true; - - /* - * Resets the selection - */ - } else if (keycode == getResetKey() && !shift) { - // Restore showing value the selected value - focusedDate.setTime(value.getTime()); - renderCalendar(); - return true; - } - - return false; - } - - /** - * Handles the keyboard navigation - * - * @param keycode - * The key code that was pressed - * @param ctrl - * Was the ctrl key pressed - * @param shift - * Was the shift key pressed - * @return Return true if key press was handled by the component, else - * return false - */ - protected boolean handleNavigation(int keycode, boolean ctrl, boolean shift) { - if (!isEnabled() || isReadonly()) { - return false; - } - - else if (resolution == VDateField.RESOLUTION_YEAR) { - return handleNavigationYearMode(keycode, ctrl, shift); - } - - else if (resolution == VDateField.RESOLUTION_MONTH) { - return handleNavigationMonthMode(keycode, ctrl, shift); - } - - else if (resolution == VDateField.RESOLUTION_DAY) { - return handleNavigationDayMode(keycode, ctrl, shift); - } - - else { - return handleNavigationDayMode(keycode, ctrl, shift); - } - - } - - /** - * Returns the reset key which will reset the calendar to the previous - * selection. By default this is backspace but it can be overriden to change - * the key to whatever you want. - * - * @return - */ - protected int getResetKey() { - return KeyCodes.KEY_BACKSPACE; - } - - /** - * Returns the select key which selects the value. By default this is the - * enter key but it can be changed to whatever you like by overriding this - * method. - * - * @return - */ - protected int getSelectKey() { - return KeyCodes.KEY_ENTER; - } - - /** - * Returns the key that closes the popup window if this is a VPopopCalendar. - * Else this does nothing. By default this is the Escape key but you can - * change the key to whatever you want by overriding this method. - * - * @return - */ - protected int getCloseKey() { - return KeyCodes.KEY_ESCAPE; - } - - /** - * The key that selects the next day in the calendar. By default this is the - * right arrow key but by overriding this method it can be changed to - * whatever you like. - * - * @return - */ - protected int getForwardKey() { - return KeyCodes.KEY_RIGHT; - } - - /** - * The key that selects the previous day in the calendar. By default this is - * the left arrow key but by overriding this method it can be changed to - * whatever you like. - * - * @return - */ - protected int getBackwardKey() { - return KeyCodes.KEY_LEFT; - } - - /** - * The key that selects the next week in the calendar. By default this is - * the down arrow key but by overriding this method it can be changed to - * whatever you like. - * - * @return - */ - protected int getNextKey() { - return KeyCodes.KEY_DOWN; - } - - /** - * The key that selects the previous week in the calendar. By default this - * is the up arrow key but by overriding this method it can be changed to - * whatever you like. - * - * @return - */ - protected int getPreviousKey() { - return KeyCodes.KEY_UP; - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.MouseOutHandler#onMouseOut(com.google - * .gwt.event.dom.client.MouseOutEvent) - */ - public void onMouseOut(MouseOutEvent event) { - if (mouseTimer != null) { - mouseTimer.cancel(); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.MouseDownHandler#onMouseDown(com.google - * .gwt.event.dom.client.MouseDownEvent) - */ - public void onMouseDown(MouseDownEvent event) { - // Allow user to click-n-hold for fast-forward or fast-rewind. - // Timer is first used for a 500ms delay after mousedown. After that has - // elapsed, another timer is triggered to go off every 150ms. Both - // timers are cancelled on mouseup or mouseout. - if (event.getSource() instanceof VEventButton) { - final Widget sender = (Widget) event.getSource(); - processClickEvent(sender); - mouseTimer = new Timer() { - @Override - public void run() { - mouseTimer = new Timer() { - @Override - public void run() { - processClickEvent(sender); - } - }; - mouseTimer.scheduleRepeating(150); - } - }; - mouseTimer.schedule(500); - } - - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.MouseUpHandler#onMouseUp(com.google.gwt - * .event.dom.client.MouseUpEvent) - */ - public void onMouseUp(MouseUpEvent event) { - if (mouseTimer != null) { - mouseTimer.cancel(); - } - } - - /** - * Sets the data of the Panel. - * - * @param currentDate - * The date to set - */ - public void setDate(Date currentDate) { - - // Check that we are not re-rendering an already active date - if (currentDate == value && currentDate != null) { - return; - } - - Date oldDisplayedMonth = displayedMonth; - value = currentDate; - - if (value == null) { - focusedDate = displayedMonth = null; - } else { - focusedDate = (Date) value.clone(); - displayedMonth = (Date) value.clone(); - } - - // Re-render calendar if month or year of focused date has changed - if (oldDisplayedMonth == null || value == null - || oldDisplayedMonth.getYear() != value.getYear() - || oldDisplayedMonth.getMonth() != value.getMonth()) { - renderCalendar(); - } else { - focusDay(currentDate); - selectFocused(); - } - - if (!hasFocus) { - focusDay((Date) null); - } - } - - /** - * TimeSelector is a widget consisting of list boxes that modifie the Date - * object that is given for. - * - */ - public class VTime extends FlowPanel implements ChangeHandler { - - private ListBox hours; - - private ListBox mins; - - private ListBox sec; - - private ListBox msec; - - private ListBox ampm; - - /** - * Constructor - */ - public VTime() { - super(); - setStyleName(VDateField.CLASSNAME + "-time"); - buildTime(); - } - - private ListBox createListBox() { - ListBox lb = new ListBox(); - lb.setStyleName(VNativeSelect.CLASSNAME); - lb.addChangeHandler(this); - lb.addBlurHandler(VCalendarPanel.this); - lb.addFocusHandler(VCalendarPanel.this); - return lb; - } - - /** - * Constructs the ListBoxes and updates their value - * - * @param redraw - * Should new instances of the listboxes be created - */ - private void buildTime() { - clear(); - - hours = createListBox(); - if (getDateTimeService().isTwelveHourClock()) { - hours.addItem("12"); - for (int i = 1; i < 12; i++) { - hours.addItem((i < 10) ? "0" + i : "" + i); - } - } else { - for (int i = 0; i < 24; i++) { - hours.addItem((i < 10) ? "0" + i : "" + i); - } - } - - hours.addChangeHandler(this); - if (getDateTimeService().isTwelveHourClock()) { - ampm = createListBox(); - final String[] ampmText = getDateTimeService().getAmPmStrings(); - ampm.addItem(ampmText[0]); - ampm.addItem(ampmText[1]); - ampm.addChangeHandler(this); - } - - if (getResolution() >= VDateField.RESOLUTION_MIN) { - mins = createListBox(); - for (int i = 0; i < 60; i++) { - mins.addItem((i < 10) ? "0" + i : "" + i); - } - mins.addChangeHandler(this); - } - if (getResolution() >= VDateField.RESOLUTION_SEC) { - sec = createListBox(); - for (int i = 0; i < 60; i++) { - sec.addItem((i < 10) ? "0" + i : "" + i); - } - sec.addChangeHandler(this); - } - if (getResolution() == VDateField.RESOLUTION_MSEC) { - msec = createListBox(); - for (int i = 0; i < 1000; i++) { - if (i < 10) { - msec.addItem("00" + i); - } else if (i < 100) { - msec.addItem("0" + i); - } else { - msec.addItem("" + i); - } - } - msec.addChangeHandler(this); - } - - final String delimiter = getDateTimeService().getClockDelimeter(); - if (isReadonly()) { - int h = 0; - if (value != null) { - h = value.getHours(); - } - if (getDateTimeService().isTwelveHourClock()) { - h -= h < 12 ? 0 : 12; - } - add(new VLabel(h < 10 ? "0" + h : "" + h)); - } else { - add(hours); - } - - if (getResolution() >= VDateField.RESOLUTION_MIN) { - add(new VLabel(delimiter)); - if (isReadonly()) { - final int m = mins.getSelectedIndex(); - add(new VLabel(m < 10 ? "0" + m : "" + m)); - } else { - add(mins); - } - } - if (getResolution() >= VDateField.RESOLUTION_SEC) { - add(new VLabel(delimiter)); - if (isReadonly()) { - final int s = sec.getSelectedIndex(); - add(new VLabel(s < 10 ? "0" + s : "" + s)); - } else { - add(sec); - } - } - if (getResolution() == VDateField.RESOLUTION_MSEC) { - add(new VLabel(".")); - if (isReadonly()) { - final int m = getMilliseconds(); - final String ms = m < 100 ? "0" + m : "" + m; - add(new VLabel(m < 10 ? "0" + ms : ms)); - } else { - add(msec); - } - } - if (getResolution() == VDateField.RESOLUTION_HOUR) { - add(new VLabel(delimiter + "00")); // o'clock - } - if (getDateTimeService().isTwelveHourClock()) { - add(new VLabel(" ")); - if (isReadonly()) { - int i = 0; - if (value != null) { - i = (value.getHours() < 12) ? 0 : 1; - } - add(new VLabel(ampm.getItemText(i))); - } else { - add(ampm); - } - } - - if (isReadonly()) { - return; - } - - // Update times - updateTimes(); - - ListBox lastDropDown = getLastDropDown(); - lastDropDown.addKeyDownHandler(new KeyDownHandler() { - public void onKeyDown(KeyDownEvent event) { - boolean shiftKey = event.getNativeEvent().getShiftKey(); - if (shiftKey) { - return; - } else { - int nativeKeyCode = event.getNativeKeyCode(); - if (nativeKeyCode == KeyCodes.KEY_TAB) { - onTabOut(event); - } - } - } - }); - - } - - private ListBox getLastDropDown() { - int i = getWidgetCount() - 1; - while (i >= 0) { - Widget widget = getWidget(i); - if (widget instanceof ListBox) { - return (ListBox) widget; - } - i--; - } - return null; - } - - /** - * Updates the valus to correspond to the values in value - */ - public void updateTimes() { - boolean selected = true; - if (value == null) { - value = new Date(); - selected = false; - } - if (getDateTimeService().isTwelveHourClock()) { - int h = value.getHours(); - ampm.setSelectedIndex(h < 12 ? 0 : 1); - h -= ampm.getSelectedIndex() * 12; - hours.setSelectedIndex(h); - } else { - hours.setSelectedIndex(value.getHours()); - } - if (getResolution() >= VDateField.RESOLUTION_MIN) { - mins.setSelectedIndex(value.getMinutes()); - } - if (getResolution() >= VDateField.RESOLUTION_SEC) { - sec.setSelectedIndex(value.getSeconds()); - } - if (getResolution() == VDateField.RESOLUTION_MSEC) { - if (selected) { - msec.setSelectedIndex(getMilliseconds()); - } else { - msec.setSelectedIndex(0); - } - } - if (getDateTimeService().isTwelveHourClock()) { - ampm.setSelectedIndex(value.getHours() < 12 ? 0 : 1); - } - - hours.setEnabled(isEnabled()); - if (mins != null) { - mins.setEnabled(isEnabled()); - } - if (sec != null) { - sec.setEnabled(isEnabled()); - } - if (msec != null) { - msec.setEnabled(isEnabled()); - } - if (ampm != null) { - ampm.setEnabled(isEnabled()); - } - - } - - private int getMilliseconds() { - return DateTimeService.getMilliseconds(value); - } - - private DateTimeService getDateTimeService() { - if (dateTimeService == null) { - dateTimeService = new DateTimeService(); - } - return dateTimeService; - } - - /* - * (non-Javadoc) VT - * - * @see - * com.google.gwt.event.dom.client.ChangeHandler#onChange(com.google.gwt - * .event.dom.client.ChangeEvent) - */ - public void onChange(ChangeEvent event) { - /* - * Value from dropdowns gets always set for the value. Like year and - * month when resolution is month or year. - */ - if (event.getSource() == hours) { - int h = hours.getSelectedIndex(); - if (getDateTimeService().isTwelveHourClock()) { - h = h + ampm.getSelectedIndex() * 12; - } - value.setHours(h); - if (timeChangeListener != null) { - timeChangeListener.changed(h, value.getMinutes(), - value.getSeconds(), - DateTimeService.getMilliseconds(value)); - } - event.preventDefault(); - event.stopPropagation(); - } else if (event.getSource() == mins) { - final int m = mins.getSelectedIndex(); - value.setMinutes(m); - if (timeChangeListener != null) { - timeChangeListener.changed(value.getHours(), m, - value.getSeconds(), - DateTimeService.getMilliseconds(value)); - } - event.preventDefault(); - event.stopPropagation(); - } else if (event.getSource() == sec) { - final int s = sec.getSelectedIndex(); - value.setSeconds(s); - if (timeChangeListener != null) { - timeChangeListener.changed(value.getHours(), - value.getMinutes(), s, - DateTimeService.getMilliseconds(value)); - } - event.preventDefault(); - event.stopPropagation(); - } else if (event.getSource() == msec) { - final int ms = msec.getSelectedIndex(); - DateTimeService.setMilliseconds(value, ms); - if (timeChangeListener != null) { - timeChangeListener.changed(value.getHours(), - value.getMinutes(), value.getSeconds(), ms); - } - event.preventDefault(); - event.stopPropagation(); - } else if (event.getSource() == ampm) { - final int h = hours.getSelectedIndex() - + (ampm.getSelectedIndex() * 12); - value.setHours(h); - if (timeChangeListener != null) { - timeChangeListener.changed(h, value.getMinutes(), - value.getSeconds(), - DateTimeService.getMilliseconds(value)); - } - event.preventDefault(); - event.stopPropagation(); - } - } - - } - - /** - * A widget representing a single day in the calendar panel. - */ - private class Day extends InlineHTML { - private static final String BASECLASS = VDateField.CLASSNAME - + "-calendarpanel-day"; - private final Date date; - - Day(Date date) { - super("" + date.getDate()); - setStyleName(BASECLASS); - this.date = date; - addClickHandler(dayClickHandler); - } - - public Date getDate() { - return date; - } - } - - public Date getDate() { - return value; - } - - /** - * If true should be returned if the panel will not be used after this - * event. - * - * @param event - * @return - */ - protected boolean onTabOut(DomEvent event) { - if (focusOutListener != null) { - return focusOutListener.onFocusOut(event); - } - return false; - } - - /** - * A focus out listener is triggered when the panel loosed focus. This can - * happen either after a user clicks outside the panel or tabs out. - * - * @param listener - * The listener to trigger - */ - public void setFocusOutListener(FocusOutListener listener) { - focusOutListener = listener; - } - - /** - * The submit listener is called when the user selects a value from the - * calender either by clicking the day or selects it by keyboard. - * - * @param submitListener - * The listener to trigger - */ - public void setSubmitListener(SubmitListener submitListener) { - this.submitListener = submitListener; - } - - /** - * The given FocusChangeListener is notified when the focused date changes - * by user either clicking on a new date or by using the keyboard. - * - * @param listener - * The FocusChangeListener to be notified - */ - public void setFocusChangeListener(FocusChangeListener listener) { - focusChangeListener = listener; - } - - /** - * The time change listener is triggered when the user changes the time. - * - * @param listener - */ - public void setTimeChangeListener(TimeChangeListener listener) { - timeChangeListener = listener; - } - - /** - * Returns the submit listener that listens to selection made from the panel - * - * @return The listener or NULL if no listener has been set - */ - public SubmitListener getSubmitListener() { - return submitListener; - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.BlurHandler#onBlur(com.google.gwt.event - * .dom.client.BlurEvent) - */ - public void onBlur(final BlurEvent event) { - if (event.getSource() instanceof VCalendarPanel) { - hasFocus = false; - focusDay(null); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.FocusHandler#onFocus(com.google.gwt.event - * .dom.client.FocusEvent) - */ - public void onFocus(FocusEvent event) { - if (event.getSource() instanceof VCalendarPanel) { - hasFocus = true; - - // Focuses the current day if the calendar shows the days - if (focusedDay != null) { - focusDay(focusedDate); - } - } - } - - private static final String SUBPART_NEXT_MONTH = "nextmon"; - private static final String SUBPART_PREV_MONTH = "prevmon"; - - private static final String SUBPART_NEXT_YEAR = "nexty"; - private static final String SUBPART_PREV_YEAR = "prevy"; - private static final String SUBPART_HOUR_SELECT = "h"; - private static final String SUBPART_MINUTE_SELECT = "m"; - private static final String SUBPART_SECS_SELECT = "s"; - private static final String SUBPART_MSECS_SELECT = "ms"; - private static final String SUBPART_AMPM_SELECT = "ampm"; - private static final String SUBPART_DAY = "day"; - private static final String SUBPART_MONTH_YEAR_HEADER = "header"; - - public String getSubPartName(Element subElement) { - if (contains(nextMonth, subElement)) { - return SUBPART_NEXT_MONTH; - } else if (contains(prevMonth, subElement)) { - return SUBPART_PREV_MONTH; - } else if (contains(nextYear, subElement)) { - return SUBPART_NEXT_YEAR; - } else if (contains(prevYear, subElement)) { - return SUBPART_PREV_YEAR; - } else if (contains(days, subElement)) { - // Day, find out which dayOfMonth and use that as the identifier - Day day = Util.findWidget(subElement, Day.class); - if (day != null) { - Date date = day.getDate(); - int id = date.getDate(); - // Zero or negative ids map to days of the preceding month, - // past-the-end-of-month ids to days of the following month - if (date.getMonth() < displayedMonth.getMonth()) { - id -= DateTimeService.getNumberOfDaysInMonth(date); - } else if (date.getMonth() > displayedMonth.getMonth()) { - id += DateTimeService - .getNumberOfDaysInMonth(displayedMonth); - } - return SUBPART_DAY + id; - } - } else if (time != null) { - if (contains(time.hours, subElement)) { - return SUBPART_HOUR_SELECT; - } else if (contains(time.mins, subElement)) { - return SUBPART_MINUTE_SELECT; - } else if (contains(time.sec, subElement)) { - return SUBPART_SECS_SELECT; - } else if (contains(time.msec, subElement)) { - return SUBPART_MSECS_SELECT; - } else if (contains(time.ampm, subElement)) { - return SUBPART_AMPM_SELECT; - - } - } else if (getCellFormatter().getElement(0, 2).isOrHasChild(subElement)) { - return SUBPART_MONTH_YEAR_HEADER; - } - - return null; - } - - /** - * Checks if subElement is inside the widget DOM hierarchy. - * - * @param w - * @param subElement - * @return true if {@code w} is a parent of subElement, false otherwise. - */ - private boolean contains(Widget w, Element subElement) { - if (w == null || w.getElement() == null) { - return false; - } - - return w.getElement().isOrHasChild(subElement); - } - - public Element getSubPartElement(String subPart) { - if (SUBPART_NEXT_MONTH.equals(subPart)) { - return nextMonth.getElement(); - } - if (SUBPART_PREV_MONTH.equals(subPart)) { - return prevMonth.getElement(); - } - if (SUBPART_NEXT_YEAR.equals(subPart)) { - return nextYear.getElement(); - } - if (SUBPART_PREV_YEAR.equals(subPart)) { - return prevYear.getElement(); - } - if (SUBPART_HOUR_SELECT.equals(subPart)) { - return time.hours.getElement(); - } - if (SUBPART_MINUTE_SELECT.equals(subPart)) { - return time.mins.getElement(); - } - if (SUBPART_SECS_SELECT.equals(subPart)) { - return time.sec.getElement(); - } - if (SUBPART_MSECS_SELECT.equals(subPart)) { - return time.msec.getElement(); - } - if (SUBPART_AMPM_SELECT.equals(subPart)) { - return time.ampm.getElement(); - } - if (subPart.startsWith(SUBPART_DAY)) { - // Zero or negative ids map to days in the preceding month, - // past-the-end-of-month ids to days in the following month - int dayOfMonth = Integer.parseInt(subPart.substring(SUBPART_DAY - .length())); - Date date = new Date(displayedMonth.getYear(), - displayedMonth.getMonth(), dayOfMonth); - Iterator iter = days.iterator(); - while (iter.hasNext()) { - Widget w = iter.next(); - if (w instanceof Day) { - Day day = (Day) w; - if (day.getDate().equals(date)) { - return day.getElement(); - } - } - } - } - - if (SUBPART_MONTH_YEAR_HEADER.equals(subPart)) { - return (Element) getCellFormatter().getElement(0, 2).getChild(0); - } - return null; - } - - @Override - protected void onDetach() { - super.onDetach(); - if (mouseTimer != null) { - mouseTimer.cancel(); - } - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import java.util.Date; +import java.util.Iterator; + +import com.google.gwt.dom.client.Node; +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.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.DomEvent; +import com.google.gwt.event.dom.client.FocusEvent; +import com.google.gwt.event.dom.client.FocusHandler; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.event.dom.client.KeyDownEvent; +import com.google.gwt.event.dom.client.KeyDownHandler; +import com.google.gwt.event.dom.client.KeyPressEvent; +import com.google.gwt.event.dom.client.KeyPressHandler; +import com.google.gwt.event.dom.client.MouseDownEvent; +import com.google.gwt.event.dom.client.MouseDownHandler; +import com.google.gwt.event.dom.client.MouseOutEvent; +import com.google.gwt.event.dom.client.MouseOutHandler; +import com.google.gwt.event.dom.client.MouseUpEvent; +import com.google.gwt.event.dom.client.MouseUpHandler; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.FlexTable; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.InlineHTML; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.DateTimeService; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VConsole; + +@SuppressWarnings("deprecation") +public class VCalendarPanel extends FocusableFlexTable implements + KeyDownHandler, KeyPressHandler, MouseOutHandler, MouseDownHandler, + MouseUpHandler, BlurHandler, FocusHandler, SubPartAware { + + public interface SubmitListener { + + /** + * Called when calendar user triggers a submitting operation in calendar + * panel. Eg. clicking on day or hitting enter. + */ + void onSubmit(); + + /** + * On eg. ESC key. + */ + void onCancel(); + } + + /** + * Blur listener that listens to blur event from the panel + */ + public interface FocusOutListener { + /** + * @return true if the calendar panel is not used after focus moves out + */ + boolean onFocusOut(DomEvent event); + } + + /** + * FocusChangeListener is notified when the panel changes its _focused_ + * value. It can be set with + */ + public interface FocusChangeListener { + void focusChanged(Date focusedDate); + } + + /** + * Dispatches an event when the panel when time is changed + */ + public interface TimeChangeListener { + + void changed(int hour, int min, int sec, int msec); + } + + /** + * Represents a Date button in the calendar + */ + private class VEventButton extends Button { + public VEventButton() { + addMouseDownHandler(VCalendarPanel.this); + addMouseOutHandler(VCalendarPanel.this); + addMouseUpHandler(VCalendarPanel.this); + } + } + + private static final String CN_FOCUSED = "focused"; + + private static final String CN_TODAY = "today"; + + private static final String CN_SELECTED = "selected"; + + /** + * Represents a click handler for when a user selects a value by using the + * mouse + */ + private ClickHandler dayClickHandler = new ClickHandler() { + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt + * .event.dom.client.ClickEvent) + */ + public void onClick(ClickEvent event) { + Day day = (Day) event.getSource(); + focusDay(day.getDay()); + selectFocused(); + onSubmit(); + } + }; + + private VEventButton prevYear; + + private VEventButton nextYear; + + private VEventButton prevMonth; + + private VEventButton nextMonth; + + private VTime time; + + private FlexTable days = new FlexTable(); + + private int resolution = VDateField.RESOLUTION_YEAR; + + private int focusedRow; + + private Timer mouseTimer; + + private Date value; + + private boolean enabled = true; + + private boolean readonly = false; + + private DateTimeService dateTimeService; + + private boolean showISOWeekNumbers; + + private Date focusedDate; + + private Day selectedDay; + + private Day focusedDay; + + private FocusOutListener focusOutListener; + + private SubmitListener submitListener; + + private FocusChangeListener focusChangeListener; + + private TimeChangeListener timeChangeListener; + + private boolean hasFocus = false; + + public VCalendarPanel() { + + setStyleName(VDateField.CLASSNAME + "-calendarpanel"); + + /* + * Firefox auto-repeat works correctly only if we use a key press + * handler, other browsers handle it correctly when using a key down + * handler + */ + if (BrowserInfo.get().isGecko()) { + addKeyPressHandler(this); + } else { + addKeyDownHandler(this); + } + addFocusHandler(this); + addBlurHandler(this); + + } + + /** + * Sets the focus to given day of current time. Used when moving in the + * calender with the keyboard. + * + * @param day + * The day number from by Date.getDate() + */ + private void focusDay(int day) { + // Only used when calender body is present + if (resolution > VDateField.RESOLUTION_MONTH) { + if (focusedDay != null) { + focusedDay.removeStyleDependentName(CN_FOCUSED); + } + + if (day > 0 && focusedDate != null) { + focusedDate.setDate(day); + int rowCount = days.getRowCount(); + for (int i = 0; i < rowCount; i++) { + int cellCount = days.getCellCount(i); + for (int j = 0; j < cellCount; j++) { + Widget widget = days.getWidget(i, j); + if (widget != null && widget instanceof Day) { + Day curday = (Day) widget; + if (curday.getDay() == day) { + curday.addStyleDependentName(CN_FOCUSED); + focusedDay = curday; + focusedRow = i; + return; + } + } + } + } + } + } + } + + /** + * Sets the selection hightlight to a given date of current time + * + * @param day + */ + private void selectDate(int day) { + if (selectedDay != null) { + selectedDay.removeStyleDependentName(CN_SELECTED); + } + + int rowCount = days.getRowCount(); + for (int i = 0; i < rowCount; i++) { + int cellCount = days.getCellCount(i); + for (int j = 0; j < cellCount; j++) { + Widget widget = days.getWidget(i, j); + if (widget != null && widget instanceof Day) { + Day curday = (Day) widget; + if (curday.getDay() == day) { + curday.addStyleDependentName(CN_SELECTED); + selectedDay = curday; + return; + } + } + } + } + } + + /** + * Updates year, month, day from focusedDate to value + */ + private void selectFocused() { + if (focusedDate != null) { + if (value == null) { + // No previously selected value (set to null on server side). + // Create a new date using current date and time + value = new Date(); + } + /* + * #5594 set Date (day) to 1 in order to prevent any kind of + * wrapping of months when later setting the month. (e.g. 31 -> + * month with 30 days -> wraps to the 1st of the following month, + * e.g. 31st of May -> 31st of April = 1st of May) + */ + value.setDate(1); + if (value.getYear() != focusedDate.getYear()) { + value.setYear(focusedDate.getYear()); + } + if (value.getMonth() != focusedDate.getMonth()) { + value.setMonth(focusedDate.getMonth()); + } + if (value.getDate() != focusedDate.getDate()) { + } + // We always need to set the date, even if it hasn't changed, since + // it was forced to 1 above. + value.setDate(focusedDate.getDate()); + + selectDate(focusedDate.getDate()); + } else { + VConsole.log("Trying to select a the focused date which is NULL!"); + } + } + + protected boolean onValueChange() { + return false; + } + + public int getResolution() { + return resolution; + } + + public void setResolution(int resolution) { + this.resolution = resolution; + if (time != null) { + time.removeFromParent(); + time = null; + } + } + + private boolean isReadonly() { + return readonly; + } + + private boolean isEnabled() { + return enabled; + } + + private void clearCalendarBody(boolean remove) { + if (!remove) { + // Leave the cells in place but clear their contents + + // This has the side effect of ensuring that the calendar always + // contain 7 rows. + for (int row = 1; row < 7; row++) { + for (int col = 0; col < 8; col++) { + days.setHTML(row, col, " "); + } + } + } else if (getRowCount() > 1) { + removeRow(1); + days.clear(); + } + } + + /** + * Builds the top buttons and current month and year header. + * + * @param needsMonth + * Should the month buttons be visible? + */ + private void buildCalendarHeader(boolean needsMonth) { + + getRowFormatter().addStyleName(0, + VDateField.CLASSNAME + "-calendarpanel-header"); + + if (prevMonth == null && needsMonth) { + prevMonth = new VEventButton(); + prevMonth.setHTML("‹"); + prevMonth.setStyleName("v-button-prevmonth"); + prevMonth.setTabIndex(-1); + nextMonth = new VEventButton(); + nextMonth.setHTML("›"); + nextMonth.setStyleName("v-button-nextmonth"); + nextMonth.setTabIndex(-1); + getFlexCellFormatter().setStyleName(0, 3, + VDateField.CLASSNAME + "-calendarpanel-nextmonth"); + getFlexCellFormatter().setStyleName(0, 1, + VDateField.CLASSNAME + "-calendarpanel-prevmonth"); + + setWidget(0, 3, nextMonth); + setWidget(0, 1, prevMonth); + } else if (prevMonth != null && !needsMonth) { + // Remove month traverse buttons + remove(prevMonth); + remove(nextMonth); + prevMonth = null; + nextMonth = null; + } + + if (prevYear == null) { + prevYear = new VEventButton(); + prevYear.setHTML("«"); + prevYear.setStyleName("v-button-prevyear"); + prevYear.setTabIndex(-1); + nextYear = new VEventButton(); + nextYear.setHTML("»"); + nextYear.setStyleName("v-button-nextyear"); + nextYear.setTabIndex(-1); + setWidget(0, 0, prevYear); + setWidget(0, 4, nextYear); + getFlexCellFormatter().setStyleName(0, 0, + VDateField.CLASSNAME + "-calendarpanel-prevyear"); + getFlexCellFormatter().setStyleName(0, 4, + VDateField.CLASSNAME + "-calendarpanel-nextyear"); + } + + final String monthName = needsMonth ? getDateTimeService().getMonth( + focusedDate.getMonth()) : ""; + final int year = focusedDate.getYear() + 1900; + getFlexCellFormatter().setStyleName(0, 2, + VDateField.CLASSNAME + "-calendarpanel-month"); + setHTML(0, 2, "" + monthName + " " + year + + ""); + } + + private DateTimeService getDateTimeService() { + return dateTimeService; + } + + public void setDateTimeService(DateTimeService dateTimeService) { + this.dateTimeService = dateTimeService; + } + + /** + * Returns whether ISO 8601 week numbers should be shown in the value + * selector or not. ISO 8601 defines that a week always starts with a Monday + * so the week numbers are only shown if this is the case. + * + * @return true if week number should be shown, false otherwise + */ + public boolean isShowISOWeekNumbers() { + return showISOWeekNumbers; + } + + public void setShowISOWeekNumbers(boolean showISOWeekNumbers) { + this.showISOWeekNumbers = showISOWeekNumbers; + } + + /** + * Builds the day and time selectors of the calendar. + */ + private void buildCalendarBody() { + + final int weekColumn = 0; + final int firstWeekdayColumn = 1; + final int headerRow = 0; + + setWidget(1, 0, days); + setCellPadding(0); + setCellSpacing(0); + getFlexCellFormatter().setColSpan(1, 0, 5); + getFlexCellFormatter().setStyleName(1, 0, + VDateField.CLASSNAME + "-calendarpanel-body"); + + days.getFlexCellFormatter().setStyleName(headerRow, weekColumn, + "v-week"); + days.setHTML(headerRow, weekColumn, ""); + // Hide the week column if week numbers are not to be displayed. + days.getFlexCellFormatter().setVisible(headerRow, weekColumn, + isShowISOWeekNumbers()); + + days.getRowFormatter().setStyleName(headerRow, + VDateField.CLASSNAME + "-calendarpanel-weekdays"); + + if (isShowISOWeekNumbers()) { + days.getFlexCellFormatter().setStyleName(headerRow, weekColumn, + "v-first"); + days.getFlexCellFormatter().setStyleName(headerRow, + firstWeekdayColumn, ""); + days.getRowFormatter().addStyleName(headerRow, + VDateField.CLASSNAME + "-calendarpanel-weeknumbers"); + } else { + days.getFlexCellFormatter().setStyleName(headerRow, weekColumn, ""); + days.getFlexCellFormatter().setStyleName(headerRow, + firstWeekdayColumn, "v-first"); + } + + days.getFlexCellFormatter().setStyleName(headerRow, + firstWeekdayColumn + 6, "v-last"); + + // Print weekday names + final int firstDay = getDateTimeService().getFirstDayOfWeek(); + for (int i = 0; i < 7; i++) { + int day = i + firstDay; + if (day > 6) { + day = 0; + } + if (getResolution() > VDateField.RESOLUTION_MONTH) { + days.setHTML(headerRow, firstWeekdayColumn + i, "" + + getDateTimeService().getShortDay(day) + ""); + } else { + days.setHTML(headerRow, firstWeekdayColumn + i, ""); + } + } + + // The day of month that is selected, -1 if no day of this month is + // selected (i.e, showing another month/year than selected or nothing is + // selected) + int dayOfMonthSelected = -1; + // The day of month that is today, -1 if no day of this month is today + // (i.e., showing another month/year than current) + int dayOfMonthToday = -1; + + boolean initiallyNull = value == null; + + if (!initiallyNull && value.getMonth() == focusedDate.getMonth() + && value.getYear() == focusedDate.getYear()) { + dayOfMonthSelected = value.getDate(); + } + final Date today = new Date(); + if (today.getMonth() == focusedDate.getMonth() + && today.getYear() == focusedDate.getYear()) { + dayOfMonthToday = today.getDate(); + } + + final int startWeekDay = getDateTimeService().getStartWeekDay( + focusedDate); + final int daysInMonth = DateTimeService + .getNumberOfDaysInMonth(focusedDate); + + int dayCount = 0; + final Date curr = new Date(focusedDate.getTime()); + + // No month has more than 6 weeks so 6 is a safe maximum for rows. + for (int weekOfMonth = 1; weekOfMonth < 7; weekOfMonth++) { + boolean weekNumberProcessed[] = new boolean[] { false, false, + false, false, false, false, false }; + + for (int dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) { + if (!(weekOfMonth == 1 && dayOfWeek < startWeekDay)) { + + if (dayCount >= daysInMonth) { + // All days printed and we are done + break; + } + + final int dayOfMonth = ++dayCount; + + curr.setDate(dayCount); + + // Actually write the day of month + Day day = new Day(dayOfMonth); + + if (dayOfMonthSelected == dayOfMonth) { + day.addStyleDependentName(CN_SELECTED); + selectedDay = day; + } + + if (dayOfMonthToday == dayOfMonth) { + day.addStyleDependentName(CN_TODAY); + } + + if (dayOfMonth == focusedDate.getDate()) { + focusedDay = day; + focusedRow = weekOfMonth; + if (hasFocus) { + day.addStyleDependentName(CN_FOCUSED); + } + } + + days.setWidget(weekOfMonth, firstWeekdayColumn + dayOfWeek, + day); + + // ISO week numbers if requested + if (!weekNumberProcessed[weekOfMonth]) { + days.getCellFormatter().setVisible(weekOfMonth, + weekColumn, isShowISOWeekNumbers()); + if (isShowISOWeekNumbers()) { + final String baseCssClass = VDateField.CLASSNAME + + "-calendarpanel-weeknumber"; + String weekCssClass = baseCssClass; + + int weekNumber = DateTimeService + .getISOWeekNumber(curr); + + days.setHTML(weekOfMonth, 0, "" + weekNumber + + ""); + weekNumberProcessed[weekOfMonth] = true; + } + + } + } + } + } + + } + + /** + * Do we need the time selector + * + * @return True if it is required + */ + private boolean isTimeSelectorNeeded() { + return getResolution() > VDateField.RESOLUTION_DAY; + } + + /** + * Updates the calendar and text field with the selected dates. + */ + public void renderCalendar() { + if (focusedDate == null) { + focusedDate = new Date(); + } + + if (getResolution() <= VDateField.RESOLUTION_MONTH + && focusChangeListener != null) { + focusChangeListener.focusChanged(new Date(focusedDate.getTime())); + } + + final boolean needsMonth = getResolution() > VDateField.RESOLUTION_YEAR; + boolean needsBody = getResolution() >= VDateField.RESOLUTION_DAY; + buildCalendarHeader(needsMonth); + clearCalendarBody(!needsBody); + if (needsBody) { + buildCalendarBody(); + } + + if (isTimeSelectorNeeded() && time == null) { + time = new VTime(); + setWidget(2, 0, time); + getFlexCellFormatter().setColSpan(2, 0, 5); + getFlexCellFormatter().setStyleName(2, 0, + VDateField.CLASSNAME + "-calendarpanel-time"); + } else if (isTimeSelectorNeeded()) { + time.updateTimes(); + } else if (time != null) { + remove(time); + } + + } + + /** + * Selects the next month + */ + private void focusNextMonth() { + + int currentMonth = focusedDate.getMonth(); + focusedDate.setMonth(currentMonth + 1); + int requestedMonth = (currentMonth + 1) % 12; + + /* + * If the selected value was e.g. 31.3 the new value would be 31.4 but + * this value is invalid so the new value will be 1.5. This is taken + * care of by decreasing the value until we have the correct month. + */ + while (focusedDate.getMonth() != requestedMonth) { + focusedDate.setDate(focusedDate.getDate() - 1); + } + + renderCalendar(); + } + + /** + * Selects the previous month + */ + private void focusPreviousMonth() { + int currentMonth = focusedDate.getMonth(); + focusedDate.setMonth(currentMonth - 1); + + /* + * If the selected value was e.g. 31.12 the new value would be 31.11 but + * this value is invalid so the new value will be 1.12. This is taken + * care of by decreasing the value until we have the correct month. + */ + while (focusedDate.getMonth() == currentMonth) { + focusedDate.setDate(focusedDate.getDate() - 1); + } + + renderCalendar(); + } + + /** + * Selects the previous year + */ + private void focusPreviousYear(int years) { + focusedDate.setYear(focusedDate.getYear() - years); + renderCalendar(); + } + + /** + * Selects the next year + */ + private void focusNextYear(int years) { + focusedDate.setYear(focusedDate.getYear() + years); + renderCalendar(); + } + + /** + * Handles a user click on the component + * + * @param sender + * The component that was clicked + * @param updateVariable + * Should the value field be updated + * + */ + private void processClickEvent(Widget sender) { + if (!isEnabled() || isReadonly()) { + return; + } + if (sender == prevYear) { + focusPreviousYear(1); + } else if (sender == nextYear) { + focusNextYear(1); + } else if (sender == prevMonth) { + focusPreviousMonth(); + } else if (sender == nextMonth) { + focusNextMonth(); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.KeyDownHandler#onKeyDown(com.google.gwt + * .event.dom.client.KeyDownEvent) + */ + public void onKeyDown(KeyDownEvent event) { + handleKeyPress(event); + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.KeyPressHandler#onKeyPress(com.google + * .gwt.event.dom.client.KeyPressEvent) + */ + public void onKeyPress(KeyPressEvent event) { + handleKeyPress(event); + } + + /** + * Handles the keypress from both the onKeyPress event and the onKeyDown + * event + * + * @param event + * The keydown/keypress event + */ + private void handleKeyPress(DomEvent event) { + if (time != null + && time.getElement().isOrHasChild( + (Node) event.getNativeEvent().getEventTarget().cast())) { + int nativeKeyCode = event.getNativeEvent().getKeyCode(); + if (nativeKeyCode == getSelectKey()) { + onSubmit(); // submit happens if enter key hit down on listboxes + event.preventDefault(); + event.stopPropagation(); + } + return; + } + + // Check tabs + int keycode = event.getNativeEvent().getKeyCode(); + if (keycode == KeyCodes.KEY_TAB && event.getNativeEvent().getShiftKey()) { + if (onTabOut(event)) { + return; + } + } + + // Handle the navigation + if (handleNavigation(keycode, event.getNativeEvent().getCtrlKey() + || event.getNativeEvent().getMetaKey(), event.getNativeEvent() + .getShiftKey())) { + event.preventDefault(); + } + + } + + /** + * Notifies submit-listeners of a submit event + */ + private void onSubmit() { + if (getSubmitListener() != null) { + getSubmitListener().onSubmit(); + } + } + + /** + * Notifies submit-listeners of a cancel event + */ + private void onCancel() { + if (getSubmitListener() != null) { + getSubmitListener().onCancel(); + } + } + + /** + * Handles the keyboard navigation when the resolution is set to years. + * + * @param keycode + * The keycode to process + * @param ctrl + * Is ctrl pressed? + * @param shift + * is shift pressed + * @return Returns true if the keycode was processed, else false + */ + protected boolean handleNavigationYearMode(int keycode, boolean ctrl, + boolean shift) { + + // Ctrl and Shift selection not supported + if (ctrl || shift) { + return false; + } + + else if (keycode == getPreviousKey()) { + focusNextYear(10); // Add 10 years + return true; + } + + else if (keycode == getForwardKey()) { + focusNextYear(1); // Add 1 year + return true; + } + + else if (keycode == getNextKey()) { + focusPreviousYear(10); // Subtract 10 years + return true; + } + + else if (keycode == getBackwardKey()) { + focusPreviousYear(1); // Subtract 1 year + return true; + + } else if (keycode == getSelectKey()) { + value = (Date) focusedDate.clone(); + onSubmit(); + return true; + + } else if (keycode == getResetKey()) { + // Restore showing value the selected value + focusedDate.setTime(value.getTime()); + renderCalendar(); + return true; + + } else if (keycode == getCloseKey()) { + // TODO fire listener, on users responsibility?? + + return true; + } + return false; + } + + /** + * Handle the keyboard navigation when the resolution is set to MONTH + * + * @param keycode + * The keycode to handle + * @param ctrl + * Was the ctrl key pressed? + * @param shift + * Was the shift key pressed? + * @return + */ + protected boolean handleNavigationMonthMode(int keycode, boolean ctrl, + boolean shift) { + + // Ctrl selection not supported + if (ctrl) { + return false; + + } else if (keycode == getPreviousKey()) { + focusNextYear(1); // Add 1 year + return true; + + } else if (keycode == getForwardKey()) { + focusNextMonth(); // Add 1 month + return true; + + } else if (keycode == getNextKey()) { + focusPreviousYear(1); // Subtract 1 year + return true; + + } else if (keycode == getBackwardKey()) { + focusPreviousMonth(); // Subtract 1 month + return true; + + } else if (keycode == getSelectKey()) { + value = (Date) focusedDate.clone(); + onSubmit(); + return true; + + } else if (keycode == getResetKey()) { + // Restore showing value the selected value + focusedDate.setTime(value.getTime()); + renderCalendar(); + return true; + + } else if (keycode == getCloseKey() || keycode == KeyCodes.KEY_TAB) { + + // TODO fire close event + + return true; + } + + return false; + } + + /** + * Handle keyboard navigation what the resolution is set to DAY + * + * @param keycode + * The keycode to handle + * @param ctrl + * Was the ctrl key pressed? + * @param shift + * Was the shift key pressed? + * @return Return true if the key press was handled by the method, else + * return false. + */ + protected boolean handleNavigationDayMode(int keycode, boolean ctrl, + boolean shift) { + + // Ctrl key is not in use + if (ctrl) { + return false; + } + + /* + * Jumps to the next day. + */ + if (keycode == getForwardKey() && !shift) { + // Calculate new showing value + + Date newCurrentDate = (Date) focusedDate.clone(); + + newCurrentDate.setDate(newCurrentDate.getDate() + 1); + + if (newCurrentDate.getMonth() == focusedDate.getMonth()) { + // Month did not change, only move the selection + focusDay(focusedDate.getDate() + 1); + } else { + // If the month changed we need to re-render the calendar + focusedDate.setDate(focusedDate.getDate() + 1); + renderCalendar(); + } + + return true; + + /* + * Jumps to the previous day + */ + } else if (keycode == getBackwardKey() && !shift) { + // Calculate new showing value + Date newCurrentDate = (Date) focusedDate.clone(); + newCurrentDate.setDate(newCurrentDate.getDate() - 1); + + if (newCurrentDate.getMonth() == focusedDate.getMonth()) { + // Month did not change, only move the selection + focusDay(focusedDate.getDate() - 1); + } else { + // If the month changed we need to re-render the calendar + focusedDate.setDate(focusedDate.getDate() - 1); + renderCalendar(); + } + + return true; + + /* + * Jumps one week back in the calendar + */ + } else if (keycode == getPreviousKey() && !shift) { + // Calculate new showing value + Date newCurrentDate = (Date) focusedDate.clone(); + newCurrentDate.setDate(newCurrentDate.getDate() - 7); + + if (newCurrentDate.getMonth() == focusedDate.getMonth() + && focusedRow > 1) { + // Month did not change, only move the selection + focusDay(focusedDate.getDate() - 7); + } else { + // If the month changed we need to re-render the calendar + focusedDate.setDate(focusedDate.getDate() - 7); + renderCalendar(); + } + + return true; + + /* + * Jumps one week forward in the calendar + */ + } else if (keycode == getNextKey() && !ctrl && !shift) { + // Calculate new showing value + Date newCurrentDate = (Date) focusedDate.clone(); + newCurrentDate.setDate(newCurrentDate.getDate() + 7); + + if (newCurrentDate.getMonth() == focusedDate.getMonth()) { + // Month did not change, only move the selection + focusDay(focusedDate.getDate() + 7); + } else { + // If the month changed we need to re-render the calendar + focusedDate.setDate(focusedDate.getDate() + 7); + renderCalendar(); + + } + + return true; + + /* + * Selects the value that is chosen + */ + } else if (keycode == getSelectKey() && !shift) { + selectFocused(); + onSubmit(); // submit + return true; + } else if (keycode == getCloseKey()) { + onCancel(); + // TODO close event + + return true; + + /* + * Jumps to the next month + */ + } else if (shift && keycode == getForwardKey()) { + focusNextMonth(); + return true; + + /* + * Jumps to the previous month + */ + } else if (shift && keycode == getBackwardKey()) { + focusPreviousMonth(); + return true; + + /* + * Jumps to the next year + */ + } else if (shift && keycode == getPreviousKey()) { + focusNextYear(1); + return true; + + /* + * Jumps to the previous year + */ + } else if (shift && keycode == getNextKey()) { + focusPreviousYear(1); + return true; + + /* + * Resets the selection + */ + } else if (keycode == getResetKey() && !shift) { + // Restore showing value the selected value + focusedDate.setTime(value.getTime()); + renderCalendar(); + return true; + } + + return false; + } + + /** + * Handles the keyboard navigation + * + * @param keycode + * The key code that was pressed + * @param ctrl + * Was the ctrl key pressed + * @param shift + * Was the shift key pressed + * @return Return true if key press was handled by the component, else + * return false + */ + protected boolean handleNavigation(int keycode, boolean ctrl, boolean shift) { + if (!isEnabled() || isReadonly()) { + return false; + } + + else if (resolution == VDateField.RESOLUTION_YEAR) { + return handleNavigationYearMode(keycode, ctrl, shift); + } + + else if (resolution == VDateField.RESOLUTION_MONTH) { + return handleNavigationMonthMode(keycode, ctrl, shift); + } + + else if (resolution == VDateField.RESOLUTION_DAY) { + return handleNavigationDayMode(keycode, ctrl, shift); + } + + else { + return handleNavigationDayMode(keycode, ctrl, shift); + } + + } + + /** + * Returns the reset key which will reset the calendar to the previous + * selection. By default this is backspace but it can be overriden to change + * the key to whatever you want. + * + * @return + */ + protected int getResetKey() { + return KeyCodes.KEY_BACKSPACE; + } + + /** + * Returns the select key which selects the value. By default this is the + * enter key but it can be changed to whatever you like by overriding this + * method. + * + * @return + */ + protected int getSelectKey() { + return KeyCodes.KEY_ENTER; + } + + /** + * Returns the key that closes the popup window if this is a VPopopCalendar. + * Else this does nothing. By default this is the Escape key but you can + * change the key to whatever you want by overriding this method. + * + * @return + */ + protected int getCloseKey() { + return KeyCodes.KEY_ESCAPE; + } + + /** + * The key that selects the next day in the calendar. By default this is the + * right arrow key but by overriding this method it can be changed to + * whatever you like. + * + * @return + */ + protected int getForwardKey() { + return KeyCodes.KEY_RIGHT; + } + + /** + * The key that selects the previous day in the calendar. By default this is + * the left arrow key but by overriding this method it can be changed to + * whatever you like. + * + * @return + */ + protected int getBackwardKey() { + return KeyCodes.KEY_LEFT; + } + + /** + * The key that selects the next week in the calendar. By default this is + * the down arrow key but by overriding this method it can be changed to + * whatever you like. + * + * @return + */ + protected int getNextKey() { + return KeyCodes.KEY_DOWN; + } + + /** + * The key that selects the previous week in the calendar. By default this + * is the up arrow key but by overriding this method it can be changed to + * whatever you like. + * + * @return + */ + protected int getPreviousKey() { + return KeyCodes.KEY_UP; + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.MouseOutHandler#onMouseOut(com.google + * .gwt.event.dom.client.MouseOutEvent) + */ + public void onMouseOut(MouseOutEvent event) { + if (mouseTimer != null) { + mouseTimer.cancel(); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.MouseDownHandler#onMouseDown(com.google + * .gwt.event.dom.client.MouseDownEvent) + */ + public void onMouseDown(MouseDownEvent event) { + // Allow user to click-n-hold for fast-forward or fast-rewind. + // Timer is first used for a 500ms delay after mousedown. After that has + // elapsed, another timer is triggered to go off every 150ms. Both + // timers are cancelled on mouseup or mouseout. + if (event.getSource() instanceof VEventButton) { + final Widget sender = (Widget) event.getSource(); + processClickEvent(sender); + mouseTimer = new Timer() { + @Override + public void run() { + mouseTimer = new Timer() { + @Override + public void run() { + processClickEvent(sender); + } + }; + mouseTimer.scheduleRepeating(150); + } + }; + mouseTimer.schedule(500); + } + + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.MouseUpHandler#onMouseUp(com.google.gwt + * .event.dom.client.MouseUpEvent) + */ + public void onMouseUp(MouseUpEvent event) { + if (mouseTimer != null) { + mouseTimer.cancel(); + } + } + + /** + * Sets the data of the Panel. + * + * @param currentDate + * The date to set + */ + public void setDate(Date currentDate) { + + // Check that we are not re-rendering an already active date + if (currentDate == value && currentDate != null) { + return; + } + + Date oldFocusedValue = focusedDate; + value = currentDate; + + if (value == null) { + focusedDate = null; + } else { + focusedDate = (Date) value.clone(); + } + + // Re-render calendar if month or year of focused date has changed + if (oldFocusedValue == null || value == null + || oldFocusedValue.getYear() != value.getYear() + || oldFocusedValue.getMonth() != value.getMonth()) { + renderCalendar(); + } else { + focusDay(currentDate.getDate()); + selectFocused(); + } + + if (!hasFocus) { + focusDay(-1); + } + } + + /** + * TimeSelector is a widget consisting of list boxes that modifie the Date + * object that is given for. + * + */ + public class VTime extends FlowPanel implements ChangeHandler { + + private ListBox hours; + + private ListBox mins; + + private ListBox sec; + + private ListBox msec; + + private ListBox ampm; + + /** + * Constructor + */ + public VTime() { + super(); + setStyleName(VDateField.CLASSNAME + "-time"); + buildTime(); + } + + private ListBox createListBox() { + ListBox lb = new ListBox(); + lb.setStyleName(VNativeSelect.CLASSNAME); + lb.addChangeHandler(this); + lb.addBlurHandler(VCalendarPanel.this); + lb.addFocusHandler(VCalendarPanel.this); + return lb; + } + + /** + * Constructs the ListBoxes and updates their value + * + * @param redraw + * Should new instances of the listboxes be created + */ + private void buildTime() { + clear(); + + hours = createListBox(); + if (getDateTimeService().isTwelveHourClock()) { + hours.addItem("12"); + for (int i = 1; i < 12; i++) { + hours.addItem((i < 10) ? "0" + i : "" + i); + } + } else { + for (int i = 0; i < 24; i++) { + hours.addItem((i < 10) ? "0" + i : "" + i); + } + } + + hours.addChangeHandler(this); + if (getDateTimeService().isTwelveHourClock()) { + ampm = createListBox(); + final String[] ampmText = getDateTimeService().getAmPmStrings(); + ampm.addItem(ampmText[0]); + ampm.addItem(ampmText[1]); + ampm.addChangeHandler(this); + } + + if (getResolution() >= VDateField.RESOLUTION_MIN) { + mins = createListBox(); + for (int i = 0; i < 60; i++) { + mins.addItem((i < 10) ? "0" + i : "" + i); + } + mins.addChangeHandler(this); + } + if (getResolution() >= VDateField.RESOLUTION_SEC) { + sec = createListBox(); + for (int i = 0; i < 60; i++) { + sec.addItem((i < 10) ? "0" + i : "" + i); + } + sec.addChangeHandler(this); + } + if (getResolution() == VDateField.RESOLUTION_MSEC) { + msec = createListBox(); + for (int i = 0; i < 1000; i++) { + if (i < 10) { + msec.addItem("00" + i); + } else if (i < 100) { + msec.addItem("0" + i); + } else { + msec.addItem("" + i); + } + } + msec.addChangeHandler(this); + } + + final String delimiter = getDateTimeService().getClockDelimeter(); + if (isReadonly()) { + int h = 0; + if (value != null) { + h = value.getHours(); + } + if (getDateTimeService().isTwelveHourClock()) { + h -= h < 12 ? 0 : 12; + } + add(new VLabel(h < 10 ? "0" + h : "" + h)); + } else { + add(hours); + } + + if (getResolution() >= VDateField.RESOLUTION_MIN) { + add(new VLabel(delimiter)); + if (isReadonly()) { + final int m = mins.getSelectedIndex(); + add(new VLabel(m < 10 ? "0" + m : "" + m)); + } else { + add(mins); + } + } + if (getResolution() >= VDateField.RESOLUTION_SEC) { + add(new VLabel(delimiter)); + if (isReadonly()) { + final int s = sec.getSelectedIndex(); + add(new VLabel(s < 10 ? "0" + s : "" + s)); + } else { + add(sec); + } + } + if (getResolution() == VDateField.RESOLUTION_MSEC) { + add(new VLabel(".")); + if (isReadonly()) { + final int m = getMilliseconds(); + final String ms = m < 100 ? "0" + m : "" + m; + add(new VLabel(m < 10 ? "0" + ms : ms)); + } else { + add(msec); + } + } + if (getResolution() == VDateField.RESOLUTION_HOUR) { + add(new VLabel(delimiter + "00")); // o'clock + } + if (getDateTimeService().isTwelveHourClock()) { + add(new VLabel(" ")); + if (isReadonly()) { + int i = 0; + if (value != null) { + i = (value.getHours() < 12) ? 0 : 1; + } + add(new VLabel(ampm.getItemText(i))); + } else { + add(ampm); + } + } + + if (isReadonly()) { + return; + } + + // Update times + updateTimes(); + + ListBox lastDropDown = getLastDropDown(); + lastDropDown.addKeyDownHandler(new KeyDownHandler() { + public void onKeyDown(KeyDownEvent event) { + boolean shiftKey = event.getNativeEvent().getShiftKey(); + if (shiftKey) { + return; + } else { + int nativeKeyCode = event.getNativeKeyCode(); + if (nativeKeyCode == KeyCodes.KEY_TAB) { + onTabOut(event); + } + } + } + }); + + } + + private ListBox getLastDropDown() { + int i = getWidgetCount() - 1; + while (i >= 0) { + Widget widget = getWidget(i); + if (widget instanceof ListBox) { + return (ListBox) widget; + } + i--; + } + return null; + } + + /** + * Updates the valus to correspond to the values in value + */ + public void updateTimes() { + boolean selected = true; + if (value == null) { + value = new Date(); + selected = false; + } + if (getDateTimeService().isTwelveHourClock()) { + int h = value.getHours(); + ampm.setSelectedIndex(h < 12 ? 0 : 1); + h -= ampm.getSelectedIndex() * 12; + hours.setSelectedIndex(h); + } else { + hours.setSelectedIndex(value.getHours()); + } + if (getResolution() >= VDateField.RESOLUTION_MIN) { + mins.setSelectedIndex(value.getMinutes()); + } + if (getResolution() >= VDateField.RESOLUTION_SEC) { + sec.setSelectedIndex(value.getSeconds()); + } + if (getResolution() == VDateField.RESOLUTION_MSEC) { + if (selected) { + msec.setSelectedIndex(getMilliseconds()); + } else { + msec.setSelectedIndex(0); + } + } + if (getDateTimeService().isTwelveHourClock()) { + ampm.setSelectedIndex(value.getHours() < 12 ? 0 : 1); + } + + hours.setEnabled(isEnabled()); + if (mins != null) { + mins.setEnabled(isEnabled()); + } + if (sec != null) { + sec.setEnabled(isEnabled()); + } + if (msec != null) { + msec.setEnabled(isEnabled()); + } + if (ampm != null) { + ampm.setEnabled(isEnabled()); + } + + } + + private int getMilliseconds() { + return DateTimeService.getMilliseconds(value); + } + + private DateTimeService getDateTimeService() { + if (dateTimeService == null) { + dateTimeService = new DateTimeService(); + } + return dateTimeService; + } + + /* + * (non-Javadoc) VT + * + * @see + * com.google.gwt.event.dom.client.ChangeHandler#onChange(com.google.gwt + * .event.dom.client.ChangeEvent) + */ + public void onChange(ChangeEvent event) { + /* + * Value from dropdowns gets always set for the value. Like year and + * month when resolution is month or year. + */ + if (event.getSource() == hours) { + int h = hours.getSelectedIndex(); + if (getDateTimeService().isTwelveHourClock()) { + h = h + ampm.getSelectedIndex() * 12; + } + value.setHours(h); + if (timeChangeListener != null) { + timeChangeListener.changed(h, value.getMinutes(), + value.getSeconds(), + DateTimeService.getMilliseconds(value)); + } + event.preventDefault(); + event.stopPropagation(); + } else if (event.getSource() == mins) { + final int m = mins.getSelectedIndex(); + value.setMinutes(m); + if (timeChangeListener != null) { + timeChangeListener.changed(value.getHours(), m, + value.getSeconds(), + DateTimeService.getMilliseconds(value)); + } + event.preventDefault(); + event.stopPropagation(); + } else if (event.getSource() == sec) { + final int s = sec.getSelectedIndex(); + value.setSeconds(s); + if (timeChangeListener != null) { + timeChangeListener.changed(value.getHours(), + value.getMinutes(), s, + DateTimeService.getMilliseconds(value)); + } + event.preventDefault(); + event.stopPropagation(); + } else if (event.getSource() == msec) { + final int ms = msec.getSelectedIndex(); + DateTimeService.setMilliseconds(value, ms); + if (timeChangeListener != null) { + timeChangeListener.changed(value.getHours(), + value.getMinutes(), value.getSeconds(), ms); + } + event.preventDefault(); + event.stopPropagation(); + } else if (event.getSource() == ampm) { + final int h = hours.getSelectedIndex() + + (ampm.getSelectedIndex() * 12); + value.setHours(h); + if (timeChangeListener != null) { + timeChangeListener.changed(h, value.getMinutes(), + value.getSeconds(), + DateTimeService.getMilliseconds(value)); + } + event.preventDefault(); + event.stopPropagation(); + } + } + + } + + private class Day extends InlineHTML { + private static final String BASECLASS = VDateField.CLASSNAME + + "-calendarpanel-day"; + private final int day; + + Day(int dayOfMonth) { + super("" + dayOfMonth); + setStyleName(BASECLASS); + day = dayOfMonth; + addClickHandler(dayClickHandler); + } + + public int getDay() { + return day; + } + } + + public Date getDate() { + return value; + } + + /** + * If true should be returned if the panel will not be used after this + * event. + * + * @param event + * @return + */ + protected boolean onTabOut(DomEvent event) { + if (focusOutListener != null) { + return focusOutListener.onFocusOut(event); + } + return false; + } + + /** + * A focus out listener is triggered when the panel loosed focus. This can + * happen either after a user clicks outside the panel or tabs out. + * + * @param listener + * The listener to trigger + */ + public void setFocusOutListener(FocusOutListener listener) { + focusOutListener = listener; + } + + /** + * The submit listener is called when the user selects a value from the + * calender either by clicking the day or selects it by keyboard. + * + * @param submitListener + * The listener to trigger + */ + public void setSubmitListener(SubmitListener submitListener) { + this.submitListener = submitListener; + } + + /** + * The given FocusChangeListener is notified when the focused date changes + * by user either clicking on a new date or by using the keyboard. + * + * @param listener + * The FocusChangeListener to be notified + */ + public void setFocusChangeListener(FocusChangeListener listener) { + focusChangeListener = listener; + } + + /** + * The time change listener is triggered when the user changes the time. + * + * @param listener + */ + public void setTimeChangeListener(TimeChangeListener listener) { + timeChangeListener = listener; + } + + /** + * Returns the submit listener that listens to selection made from the panel + * + * @return The listener or NULL if no listener has been set + */ + public SubmitListener getSubmitListener() { + return submitListener; + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.BlurHandler#onBlur(com.google.gwt.event + * .dom.client.BlurEvent) + */ + public void onBlur(final BlurEvent event) { + if (event.getSource() instanceof VCalendarPanel) { + hasFocus = false; + focusDay(-1); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.FocusHandler#onFocus(com.google.gwt.event + * .dom.client.FocusEvent) + */ + public void onFocus(FocusEvent event) { + if (event.getSource() instanceof VCalendarPanel) { + hasFocus = true; + + // Focuses the current day if the calendar shows the days + if (focusedDay != null) { + focusDay(focusedDay.getDay()); + } + } + } + + private static final String SUBPART_NEXT_MONTH = "nextmon"; + private static final String SUBPART_PREV_MONTH = "prevmon"; + + private static final String SUBPART_NEXT_YEAR = "nexty"; + private static final String SUBPART_PREV_YEAR = "prevy"; + private static final String SUBPART_HOUR_SELECT = "h"; + private static final String SUBPART_MINUTE_SELECT = "m"; + private static final String SUBPART_SECS_SELECT = "s"; + private static final String SUBPART_MSECS_SELECT = "ms"; + private static final String SUBPART_AMPM_SELECT = "ampm"; + private static final String SUBPART_DAY = "day"; + private static final String SUBPART_MONTH_YEAR_HEADER = "header"; + + public String getSubPartName(Element subElement) { + if (contains(nextMonth, subElement)) { + return SUBPART_NEXT_MONTH; + } else if (contains(prevMonth, subElement)) { + return SUBPART_PREV_MONTH; + } else if (contains(nextYear, subElement)) { + return SUBPART_NEXT_YEAR; + } else if (contains(prevYear, subElement)) { + return SUBPART_PREV_YEAR; + } else if (contains(days, subElement)) { + // Day, find out which dayOfMonth and use that as the identifier + Day day = Util.findWidget(subElement, Day.class); + if (day != null) { + return SUBPART_DAY + day.getDay(); + } + } else if (time != null) { + if (contains(time.hours, subElement)) { + return SUBPART_HOUR_SELECT; + } else if (contains(time.mins, subElement)) { + return SUBPART_MINUTE_SELECT; + } else if (contains(time.sec, subElement)) { + return SUBPART_SECS_SELECT; + } else if (contains(time.msec, subElement)) { + return SUBPART_MSECS_SELECT; + } else if (contains(time.ampm, subElement)) { + return SUBPART_AMPM_SELECT; + + } + } else if (getCellFormatter().getElement(0, 2).isOrHasChild(subElement)) { + return SUBPART_MONTH_YEAR_HEADER; + } + + return null; + } + + /** + * Checks if subElement is inside the widget DOM hierarchy. + * + * @param w + * @param subElement + * @return true if {@code w} is a parent of subElement, false otherwise. + */ + private boolean contains(Widget w, Element subElement) { + if (w == null || w.getElement() == null) { + return false; + } + + return w.getElement().isOrHasChild(subElement); + } + + public Element getSubPartElement(String subPart) { + if (SUBPART_NEXT_MONTH.equals(subPart)) { + return nextMonth.getElement(); + } + if (SUBPART_PREV_MONTH.equals(subPart)) { + return prevMonth.getElement(); + } + if (SUBPART_NEXT_YEAR.equals(subPart)) { + return nextYear.getElement(); + } + if (SUBPART_PREV_YEAR.equals(subPart)) { + return prevYear.getElement(); + } + if (SUBPART_HOUR_SELECT.equals(subPart)) { + return time.hours.getElement(); + } + if (SUBPART_MINUTE_SELECT.equals(subPart)) { + return time.mins.getElement(); + } + if (SUBPART_SECS_SELECT.equals(subPart)) { + return time.sec.getElement(); + } + if (SUBPART_MSECS_SELECT.equals(subPart)) { + return time.msec.getElement(); + } + if (SUBPART_AMPM_SELECT.equals(subPart)) { + return time.ampm.getElement(); + } + if (subPart.startsWith(SUBPART_DAY)) { + int dayOfMonth = Integer.parseInt(subPart.substring(SUBPART_DAY + .length())); + Iterator iter = days.iterator(); + while (iter.hasNext()) { + Widget w = iter.next(); + if (w instanceof Day) { + Day day = (Day) w; + if (day.getDay() == dayOfMonth) { + return day.getElement(); + } + } + } + } + + if (SUBPART_MONTH_YEAR_HEADER.equals(subPart)) { + return (Element) getCellFormatter().getElement(0, 2).getChild(0); + } + return null; + } + + @Override + protected void onDetach() { + super.onDetach(); + if (mouseTimer != null) { + mouseTimer.cancel(); + } + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDateField.java b/src/com/vaadin/terminal/gwt/client/ui/VDateField.java index 1ac697baa9..bc228675b2 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VDateField.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VDateField.java @@ -1,277 +1,277 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.Date; - -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.ui.FlowPanel; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.DateTimeService; -import com.vaadin.terminal.gwt.client.LocaleNotLoadedException; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.VTooltip; - -public class VDateField extends FlowPanel implements Paintable, Field { - - public static final String CLASSNAME = "v-datefield"; - - private String id; - - private ApplicationConnection client; - - protected boolean immediate; - - public static final int RESOLUTION_YEAR = 1; - public static final int RESOLUTION_MONTH = 2; - public static final int RESOLUTION_DAY = 4; - public static final int RESOLUTION_HOUR = 8; - public static final int RESOLUTION_MIN = 16; - public static final int RESOLUTION_SEC = 32; - public static final int RESOLUTION_MSEC = 64; - - public static final String WEEK_NUMBERS = "wn"; - - static String resolutionToString(int res) { - if (res > RESOLUTION_DAY) { - return "full"; - } - if (res == RESOLUTION_DAY) { - return "day"; - } - if (res == RESOLUTION_MONTH) { - return "month"; - } - return "year"; - } - - protected int currentResolution = RESOLUTION_YEAR; - - protected String currentLocale; - - protected boolean readonly; - - protected boolean enabled; - - /** - * The date that is selected in the date field. Null if an invalid date is - * specified. - */ - private Date date = null; - - protected DateTimeService dts; - - private boolean showISOWeekNumbers = false; - - public VDateField() { - setStyleName(CLASSNAME); - dts = new DateTimeService(); - sinkEvents(VTooltip.TOOLTIP_EVENTS); - } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (client != null) { - client.handleTooltipEvent(event, this); - } - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - // Ensure correct implementation and let layout manage caption - if (client.updateComponent(this, uidl, true)) { - return; - } - - // Save details - this.client = client; - id = uidl.getId(); - immediate = uidl.getBooleanAttribute("immediate"); - - readonly = uidl.getBooleanAttribute("readonly"); - enabled = !uidl.getBooleanAttribute("disabled"); - - if (uidl.hasAttribute("locale")) { - final String locale = uidl.getStringAttribute("locale"); - try { - dts.setLocale(locale); - currentLocale = locale; - } catch (final LocaleNotLoadedException e) { - currentLocale = dts.getLocale(); - VConsole.error("Tried to use an unloaded locale \"" + locale - + "\". Using default locale (" + currentLocale + ")."); - VConsole.error(e); - } - } - - // We show week numbers only if the week starts with Monday, as ISO 8601 - // specifies - showISOWeekNumbers = uidl.getBooleanAttribute(WEEK_NUMBERS) - && dts.getFirstDayOfWeek() == 1; - - int newResolution; - if (uidl.hasVariable("msec")) { - newResolution = RESOLUTION_MSEC; - } else if (uidl.hasVariable("sec")) { - newResolution = RESOLUTION_SEC; - } else if (uidl.hasVariable("min")) { - newResolution = RESOLUTION_MIN; - } else if (uidl.hasVariable("hour")) { - newResolution = RESOLUTION_HOUR; - } else if (uidl.hasVariable("day")) { - newResolution = RESOLUTION_DAY; - } else if (uidl.hasVariable("month")) { - newResolution = RESOLUTION_MONTH; - } else { - newResolution = RESOLUTION_YEAR; - } - - currentResolution = newResolution; - - // Add stylename that indicates current resolution - addStyleName(CLASSNAME + "-" + resolutionToString(currentResolution)); - - final int year = uidl.getIntVariable("year"); - final int month = (currentResolution >= RESOLUTION_MONTH) ? uidl - .getIntVariable("month") : -1; - final int day = (currentResolution >= RESOLUTION_DAY) ? uidl - .getIntVariable("day") : -1; - final int hour = (currentResolution >= RESOLUTION_HOUR) ? uidl - .getIntVariable("hour") : 0; - final int min = (currentResolution >= RESOLUTION_MIN) ? uidl - .getIntVariable("min") : 0; - final int sec = (currentResolution >= RESOLUTION_SEC) ? uidl - .getIntVariable("sec") : 0; - final int msec = (currentResolution >= RESOLUTION_MSEC) ? uidl - .getIntVariable("msec") : 0; - - // Construct new date for this datefield (only if not null) - if (year > -1) { - setCurrentDate(new Date((long) getTime(year, month, day, hour, min, - sec, msec))); - } else { - setCurrentDate(null); - } - } - - /* - * We need this redundant native function because Java's Date object doesn't - * have a setMilliseconds method. - */ - private static native double getTime(int y, int m, int d, int h, int mi, - int s, int ms) - /*-{ - try { - var date = new Date(2000,1,1,1); // don't use current date here - if(y && y >= 0) date.setFullYear(y); - if(m && m >= 1) date.setMonth(m-1); - if(d && d >= 0) date.setDate(d); - if(h >= 0) date.setHours(h); - if(mi >= 0) date.setMinutes(mi); - if(s >= 0) date.setSeconds(s); - if(ms >= 0) date.setMilliseconds(ms); - return date.getTime(); - } catch (e) { - // TODO print some error message on the console - //console.log(e); - return (new Date()).getTime(); - } - }-*/; - - public int getMilliseconds() { - return DateTimeService.getMilliseconds(date); - } - - public void setMilliseconds(int ms) { - DateTimeService.setMilliseconds(date, ms); - } - - public int getCurrentResolution() { - return currentResolution; - } - - public void setCurrentResolution(int currentResolution) { - this.currentResolution = currentResolution; - } - - public String getCurrentLocale() { - return currentLocale; - } - - public void setCurrentLocale(String currentLocale) { - this.currentLocale = currentLocale; - } - - public Date getCurrentDate() { - return date; - } - - public void setCurrentDate(Date date) { - this.date = date; - } - - public boolean isImmediate() { - return immediate; - } - - public boolean isReadonly() { - return readonly; - } - - public boolean isEnabled() { - return enabled; - } - - public DateTimeService getDateTimeService() { - return dts; - } - - public String getId() { - return id; - } - - public ApplicationConnection getClient() { - return client; - } - - /** - * Returns whether ISO 8601 week numbers should be shown in the date - * selector or not. ISO 8601 defines that a week always starts with a Monday - * so the week numbers are only shown if this is the case. - * - * @return true if week number should be shown, false otherwise - */ - public boolean isShowISOWeekNumbers() { - return showISOWeekNumbers; - } - - /** - * Returns a copy of the current date. Modifying the returned date will not - * modify the value of this VDateField. Use {@link #setDate(Date)} to change - * the current date. - * - * @return A copy of the current date - */ - protected Date getDate() { - Date current = getCurrentDate(); - if (current == null) { - return null; - } else { - return (Date) getCurrentDate().clone(); - } - } - - /** - * Sets the current date for this VDateField. - * - * @param date - * The new date to use - */ - protected void setDate(Date date) { - this.date = date; - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import java.util.Date; + +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.FlowPanel; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.DateTimeService; +import com.vaadin.terminal.gwt.client.LocaleNotLoadedException; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.VTooltip; + +public class VDateField extends FlowPanel implements Paintable, Field { + + public static final String CLASSNAME = "v-datefield"; + + private String id; + + private ApplicationConnection client; + + protected boolean immediate; + + public static final int RESOLUTION_YEAR = 1; + public static final int RESOLUTION_MONTH = 2; + public static final int RESOLUTION_DAY = 4; + public static final int RESOLUTION_HOUR = 8; + public static final int RESOLUTION_MIN = 16; + public static final int RESOLUTION_SEC = 32; + public static final int RESOLUTION_MSEC = 64; + + public static final String WEEK_NUMBERS = "wn"; + + static String resolutionToString(int res) { + if (res > RESOLUTION_DAY) { + return "full"; + } + if (res == RESOLUTION_DAY) { + return "day"; + } + if (res == RESOLUTION_MONTH) { + return "month"; + } + return "year"; + } + + protected int currentResolution = RESOLUTION_YEAR; + + protected String currentLocale; + + protected boolean readonly; + + protected boolean enabled; + + /** + * The date that is selected in the date field. Null if an invalid date is + * specified. + */ + private Date date = null; + + protected DateTimeService dts; + + private boolean showISOWeekNumbers = false; + + public VDateField() { + setStyleName(CLASSNAME); + dts = new DateTimeService(); + sinkEvents(VTooltip.TOOLTIP_EVENTS); + } + + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + if (client != null) { + client.handleTooltipEvent(event, this); + } + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + // Ensure correct implementation and let layout manage caption + if (client.updateComponent(this, uidl, true)) { + return; + } + + // Save details + this.client = client; + id = uidl.getId(); + immediate = uidl.getBooleanAttribute("immediate"); + + readonly = uidl.getBooleanAttribute("readonly"); + enabled = !uidl.getBooleanAttribute("disabled"); + + if (uidl.hasAttribute("locale")) { + final String locale = uidl.getStringAttribute("locale"); + try { + dts.setLocale(locale); + currentLocale = locale; + } catch (final LocaleNotLoadedException e) { + currentLocale = dts.getLocale(); + VConsole.error("Tried to use an unloaded locale \"" + locale + + "\". Using default locale (" + currentLocale + ")."); + VConsole.error(e); + } + } + + // We show week numbers only if the week starts with Monday, as ISO 8601 + // specifies + showISOWeekNumbers = uidl.getBooleanAttribute(WEEK_NUMBERS) + && dts.getFirstDayOfWeek() == 1; + + int newResolution; + if (uidl.hasVariable("msec")) { + newResolution = RESOLUTION_MSEC; + } else if (uidl.hasVariable("sec")) { + newResolution = RESOLUTION_SEC; + } else if (uidl.hasVariable("min")) { + newResolution = RESOLUTION_MIN; + } else if (uidl.hasVariable("hour")) { + newResolution = RESOLUTION_HOUR; + } else if (uidl.hasVariable("day")) { + newResolution = RESOLUTION_DAY; + } else if (uidl.hasVariable("month")) { + newResolution = RESOLUTION_MONTH; + } else { + newResolution = RESOLUTION_YEAR; + } + + currentResolution = newResolution; + + // Add stylename that indicates current resolution + addStyleName(CLASSNAME + "-" + resolutionToString(currentResolution)); + + final int year = uidl.getIntVariable("year"); + final int month = (currentResolution >= RESOLUTION_MONTH) ? uidl + .getIntVariable("month") : -1; + final int day = (currentResolution >= RESOLUTION_DAY) ? uidl + .getIntVariable("day") : -1; + final int hour = (currentResolution >= RESOLUTION_HOUR) ? uidl + .getIntVariable("hour") : 0; + final int min = (currentResolution >= RESOLUTION_MIN) ? uidl + .getIntVariable("min") : 0; + final int sec = (currentResolution >= RESOLUTION_SEC) ? uidl + .getIntVariable("sec") : 0; + final int msec = (currentResolution >= RESOLUTION_MSEC) ? uidl + .getIntVariable("msec") : 0; + + // Construct new date for this datefield (only if not null) + if (year > -1) { + setCurrentDate(new Date((long) getTime(year, month, day, hour, min, + sec, msec))); + } else { + setCurrentDate(null); + } + } + + /* + * We need this redundant native function because Java's Date object doesn't + * have a setMilliseconds method. + */ + private static native double getTime(int y, int m, int d, int h, int mi, + int s, int ms) + /*-{ + try { + var date = new Date(2000,1,1,1); // don't use current date here + if(y && y >= 0) date.setFullYear(y); + if(m && m >= 1) date.setMonth(m-1); + if(d && d >= 0) date.setDate(d); + if(h >= 0) date.setHours(h); + if(mi >= 0) date.setMinutes(mi); + if(s >= 0) date.setSeconds(s); + if(ms >= 0) date.setMilliseconds(ms); + return date.getTime(); + } catch (e) { + // TODO print some error message on the console + //console.log(e); + return (new Date()).getTime(); + } + }-*/; + + public int getMilliseconds() { + return DateTimeService.getMilliseconds(date); + } + + public void setMilliseconds(int ms) { + DateTimeService.setMilliseconds(date, ms); + } + + public int getCurrentResolution() { + return currentResolution; + } + + public void setCurrentResolution(int currentResolution) { + this.currentResolution = currentResolution; + } + + public String getCurrentLocale() { + return currentLocale; + } + + public void setCurrentLocale(String currentLocale) { + this.currentLocale = currentLocale; + } + + public Date getCurrentDate() { + return date; + } + + public void setCurrentDate(Date date) { + this.date = date; + } + + public boolean isImmediate() { + return immediate; + } + + public boolean isReadonly() { + return readonly; + } + + public boolean isEnabled() { + return enabled; + } + + public DateTimeService getDateTimeService() { + return dts; + } + + public String getId() { + return id; + } + + public ApplicationConnection getClient() { + return client; + } + + /** + * Returns whether ISO 8601 week numbers should be shown in the date + * selector or not. ISO 8601 defines that a week always starts with a Monday + * so the week numbers are only shown if this is the case. + * + * @return true if week number should be shown, false otherwise + */ + public boolean isShowISOWeekNumbers() { + return showISOWeekNumbers; + } + + /** + * Returns a copy of the current date. Modifying the returned date will not + * modify the value of this VDateField. Use {@link #setDate(Date)} to change + * the current date. + * + * @return A copy of the current date + */ + protected Date getDate() { + Date current = getCurrentDate(); + if (current == null) { + return null; + } else { + return (Date) getCurrentDate().clone(); + } + } + + /** + * Sets the current date for this VDateField. + * + * @param date + * The new date to use + */ + protected void setDate(Date date) { + this.date = date; + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java index 73bfe27700..91388edcaf 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java @@ -1,153 +1,153 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.Date; - -import com.google.gwt.event.dom.client.DomEvent; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.DateTimeService; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener; - -/** - * A client side implementation for InlineDateField - */ -public class VDateFieldCalendar extends VDateField { - - private final VCalendarPanel calendarPanel; - - public VDateFieldCalendar() { - super(); - calendarPanel = new VCalendarPanel(); - add(calendarPanel); - calendarPanel.setSubmitListener(new SubmitListener() { - public void onSubmit() { - updateValueFromPanel(); - } - - public void onCancel() { - // TODO Auto-generated method stub - - } - }); - calendarPanel.setFocusOutListener(new FocusOutListener() { - public boolean onFocusOut(DomEvent event) { - updateValueFromPanel(); - return false; - } - }); - } - - @Override - @SuppressWarnings("deprecation") - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - super.updateFromUIDL(uidl, client); - calendarPanel.setShowISOWeekNumbers(isShowISOWeekNumbers()); - calendarPanel.setDateTimeService(getDateTimeService()); - calendarPanel.setResolution(getCurrentResolution()); - Date currentDate = getCurrentDate(); - if (currentDate != null) { - calendarPanel.setDate(new Date(currentDate.getTime())); - } else { - calendarPanel.setDate(null); - } - - if (currentResolution > RESOLUTION_DAY) { - calendarPanel.setTimeChangeListener(new TimeChangeListener() { - public void changed(int hour, int min, int sec, int msec) { - Date d = getDate(); - if (d == null) { - // date currently null, use the value from calendarPanel - // (~ client time at the init of the widget) - d = (Date) calendarPanel.getDate().clone(); - } - d.setHours(hour); - d.setMinutes(min); - d.setSeconds(sec); - DateTimeService.setMilliseconds(d, msec); - - // Always update time changes to the server - calendarPanel.setDate(d); - updateValueFromPanel(); - } - }); - } - - if (currentResolution <= RESOLUTION_MONTH) { - calendarPanel.setFocusChangeListener(new FocusChangeListener() { - public void focusChanged(Date date) { - Date date2 = new Date(); - if (calendarPanel.getDate() != null) { - date2.setTime(calendarPanel.getDate().getTime()); - } - /* - * Update the value of calendarPanel - */ - date2.setYear(date.getYear()); - date2.setMonth(date.getMonth()); - calendarPanel.setDate(date2); - /* - * Then update the value from panel to server - */ - updateValueFromPanel(); - } - }); - } else { - calendarPanel.setFocusChangeListener(null); - } - - // Update possible changes - calendarPanel.renderCalendar(); - } - - /** - * TODO refactor: almost same method as in VPopupCalendar.updateValue - */ - @SuppressWarnings("deprecation") - private void updateValueFromPanel() { - Date date2 = calendarPanel.getDate(); - Date currentDate = getCurrentDate(); - if (currentDate == null || date2.getTime() != currentDate.getTime()) { - setCurrentDate((Date) date2.clone()); - getClient().updateVariable(getId(), "year", date2.getYear() + 1900, - false); - if (getCurrentResolution() > VDateField.RESOLUTION_YEAR) { - getClient().updateVariable(getId(), "month", - date2.getMonth() + 1, false); - if (getCurrentResolution() > RESOLUTION_MONTH) { - getClient().updateVariable(getId(), "day", date2.getDate(), - false); - if (getCurrentResolution() > RESOLUTION_DAY) { - getClient().updateVariable(getId(), "hour", - date2.getHours(), false); - if (getCurrentResolution() > RESOLUTION_HOUR) { - getClient().updateVariable(getId(), "min", - date2.getMinutes(), false); - if (getCurrentResolution() > RESOLUTION_MIN) { - getClient().updateVariable(getId(), "sec", - date2.getSeconds(), false); - if (getCurrentResolution() > RESOLUTION_SEC) { - getClient().updateVariable( - getId(), - "msec", - DateTimeService - .getMilliseconds(date2), - false); - } - } - } - } - } - } - if (isImmediate()) { - getClient().sendPendingVariableChanges(); - } - } - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import java.util.Date; + +import com.google.gwt.event.dom.client.DomEvent; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.DateTimeService; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener; +import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener; +import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener; +import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener; + +/** + * A client side implementation for InlineDateField + */ +public class VDateFieldCalendar extends VDateField { + + private final VCalendarPanel calendarPanel; + + public VDateFieldCalendar() { + super(); + calendarPanel = new VCalendarPanel(); + add(calendarPanel); + calendarPanel.setSubmitListener(new SubmitListener() { + public void onSubmit() { + updateValueFromPanel(); + } + + public void onCancel() { + // TODO Auto-generated method stub + + } + }); + calendarPanel.setFocusOutListener(new FocusOutListener() { + public boolean onFocusOut(DomEvent event) { + updateValueFromPanel(); + return false; + } + }); + } + + @Override + @SuppressWarnings("deprecation") + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + super.updateFromUIDL(uidl, client); + calendarPanel.setShowISOWeekNumbers(isShowISOWeekNumbers()); + calendarPanel.setDateTimeService(getDateTimeService()); + calendarPanel.setResolution(getCurrentResolution()); + Date currentDate = getCurrentDate(); + if (currentDate != null) { + calendarPanel.setDate(new Date(currentDate.getTime())); + } else { + calendarPanel.setDate(null); + } + + if (currentResolution > RESOLUTION_DAY) { + calendarPanel.setTimeChangeListener(new TimeChangeListener() { + public void changed(int hour, int min, int sec, int msec) { + Date d = getDate(); + if (d == null) { + // date currently null, use the value from calendarPanel + // (~ client time at the init of the widget) + d = (Date) calendarPanel.getDate().clone(); + } + d.setHours(hour); + d.setMinutes(min); + d.setSeconds(sec); + DateTimeService.setMilliseconds(d, msec); + + // Always update time changes to the server + calendarPanel.setDate(d); + updateValueFromPanel(); + } + }); + } + + if (currentResolution <= RESOLUTION_MONTH) { + calendarPanel.setFocusChangeListener(new FocusChangeListener() { + public void focusChanged(Date date) { + Date date2 = new Date(); + if (calendarPanel.getDate() != null) { + date2.setTime(calendarPanel.getDate().getTime()); + } + /* + * Update the value of calendarPanel + */ + date2.setYear(date.getYear()); + date2.setMonth(date.getMonth()); + calendarPanel.setDate(date2); + /* + * Then update the value from panel to server + */ + updateValueFromPanel(); + } + }); + } else { + calendarPanel.setFocusChangeListener(null); + } + + // Update possible changes + calendarPanel.renderCalendar(); + } + + /** + * TODO refactor: almost same method as in VPopupCalendar.updateValue + */ + @SuppressWarnings("deprecation") + private void updateValueFromPanel() { + Date date2 = calendarPanel.getDate(); + Date currentDate = getCurrentDate(); + if (currentDate == null || date2.getTime() != currentDate.getTime()) { + setCurrentDate((Date) date2.clone()); + getClient().updateVariable(getId(), "year", date2.getYear() + 1900, + false); + if (getCurrentResolution() > VDateField.RESOLUTION_YEAR) { + getClient().updateVariable(getId(), "month", + date2.getMonth() + 1, false); + if (getCurrentResolution() > RESOLUTION_MONTH) { + getClient().updateVariable(getId(), "day", date2.getDate(), + false); + if (getCurrentResolution() > RESOLUTION_DAY) { + getClient().updateVariable(getId(), "hour", + date2.getHours(), false); + if (getCurrentResolution() > RESOLUTION_HOUR) { + getClient().updateVariable(getId(), "min", + date2.getMinutes(), false); + if (getCurrentResolution() > RESOLUTION_MIN) { + getClient().updateVariable(getId(), "sec", + date2.getSeconds(), false); + if (getCurrentResolution() > RESOLUTION_SEC) { + getClient().updateVariable( + getId(), + "msec", + DateTimeService + .getMilliseconds(date2), + false); + } + } + } + } + } + } + if (isImmediate()) { + getClient().sendPendingVariableChanges(); + } + } + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VForm.java b/src/com/vaadin/terminal/gwt/client/ui/VForm.java index 3b38ecb487..c0a6e5b275 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VForm.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VForm.java @@ -1,331 +1,331 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.Set; - -import com.google.gwt.dom.client.Style.Display; -import com.google.gwt.event.dom.client.KeyDownEvent; -import com.google.gwt.event.dom.client.KeyDownHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.ui.ComplexPanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderInformation; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.VErrorMessage; - -public class VForm extends ComplexPanel implements Container, KeyDownHandler { - - protected String id; - - private String height = ""; - - private String width = ""; - - public static final String CLASSNAME = "v-form"; - - private Container lo; - private Element legend = DOM.createLegend(); - private Element caption = DOM.createSpan(); - private Element errorIndicatorElement = DOM.createDiv(); - private Element desc = DOM.createDiv(); - private Icon icon; - private VErrorMessage errorMessage = new VErrorMessage(); - - private Element fieldContainer = DOM.createDiv(); - - private Element footerContainer = DOM.createDiv(); - - private Element fieldSet = DOM.createFieldSet(); - - private Container footer; - - private ApplicationConnection client; - - private RenderInformation renderInformation = new RenderInformation(); - - private int borderPaddingHorizontal = -1; - - private boolean rendering = false; - - ShortcutActionHandler shortcutHandler; - - private HandlerRegistration keyDownRegistration; - - public VForm() { - setElement(DOM.createDiv()); - getElement().appendChild(fieldSet); - setStyleName(CLASSNAME); - fieldSet.appendChild(legend); - legend.appendChild(caption); - errorIndicatorElement.setClassName("v-errorindicator"); - errorIndicatorElement.getStyle().setDisplay(Display.NONE); - errorIndicatorElement.setInnerText(" "); // needed for IE - desc.setClassName("v-form-description"); - fieldSet.appendChild(desc); // Adding description for initial padding - // measurements, removed later if no - // description is set - fieldSet.appendChild(fieldContainer); - errorMessage.setVisible(false); - errorMessage.setStyleName(CLASSNAME + "-errormessage"); - fieldSet.appendChild(errorMessage.getElement()); - fieldSet.appendChild(footerContainer); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - rendering = true; - this.client = client; - id = uidl.getId(); - - if (client.updateComponent(this, uidl, false)) { - rendering = false; - return; - } - - boolean legendEmpty = true; - if (uidl.hasAttribute("caption")) { - caption.setInnerText(uidl.getStringAttribute("caption")); - legendEmpty = false; - } else { - caption.setInnerText(""); - } - if (uidl.hasAttribute("icon")) { - if (icon == null) { - icon = new Icon(client); - legend.insertFirst(icon.getElement()); - } - icon.setUri(uidl.getStringAttribute("icon")); - legendEmpty = false; - } else { - if (icon != null) { - legend.removeChild(icon.getElement()); - } - } - if (legendEmpty) { - addStyleDependentName("nocaption"); - } else { - removeStyleDependentName("nocaption"); - } - - if (uidl.hasAttribute("error")) { - final UIDL errorUidl = uidl.getErrors(); - errorMessage.updateFromUIDL(errorUidl); - errorMessage.setVisible(true); - - } else { - errorMessage.setVisible(false); - } - - if (uidl.hasAttribute("description")) { - desc.setInnerHTML(uidl.getStringAttribute("description")); - if (desc.getParentElement() == null) { - fieldSet.insertAfter(desc, legend); - } - } else { - desc.setInnerHTML(""); - if (desc.getParentElement() != null) { - fieldSet.removeChild(desc); - } - } - - updateSize(); - - // first render footer so it will be easier to handle relative height of - // main layout - if (uidl.getChildCount() > 1 - && !uidl.getChildUIDL(1).getTag().equals("actions")) { - // render footer - Container newFooter = (Container) client.getPaintable(uidl - .getChildUIDL(1)); - if (footer == null) { - add((Widget) newFooter, footerContainer); - footer = newFooter; - } else if (newFooter != footer) { - remove((Widget) footer); - client.unregisterPaintable(footer); - add((Widget) newFooter, footerContainer); - } - footer = newFooter; - footer.updateFromUIDL(uidl.getChildUIDL(1), client); - // needed for the main layout to know the space it has available - updateSize(); - } else { - if (footer != null) { - remove((Widget) footer); - client.unregisterPaintable(footer); - // needed for the main layout to know the space it has available - updateSize(); - } - } - - final UIDL layoutUidl = uidl.getChildUIDL(0); - Container newLo = (Container) client.getPaintable(layoutUidl); - if (lo == null) { - lo = newLo; - add((Widget) lo, fieldContainer); - } else if (lo != newLo) { - client.unregisterPaintable(lo); - remove((Widget) lo); - lo = newLo; - add((Widget) lo, fieldContainer); - } - lo.updateFromUIDL(layoutUidl, client); - - // also recalculates size of the footer if undefined size form - see - // #3710 - updateSize(); - client.runDescendentsLayout(this); - - // We may have actions attached - if (uidl.getChildCount() > 1) { - UIDL childUidl = uidl.getChildByTagName("actions"); - if (childUidl != null) { - if (shortcutHandler == null) { - shortcutHandler = new ShortcutActionHandler(id, client); - keyDownRegistration = addDomHandler(this, - KeyDownEvent.getType()); - } - shortcutHandler.updateActionMap(childUidl); - } - } else if (shortcutHandler != null) { - keyDownRegistration.removeHandler(); - shortcutHandler = null; - keyDownRegistration = null; - } - - rendering = false; - } - - public void updateSize() { - - renderInformation.updateSize(getElement()); - - renderInformation.setContentAreaHeight(renderInformation - .getRenderedSize().getHeight() - getSpaceConsumedVertically()); - if (BrowserInfo.get().isIE6()) { - getElement().getStyle().setProperty("overflow", "hidden"); - } - renderInformation.setContentAreaWidth(renderInformation - .getRenderedSize().getWidth() - borderPaddingHorizontal); - } - - public RenderSpace getAllocatedSpace(Widget child) { - if (child == lo) { - return renderInformation.getContentAreaSize(); - } else if (child == footer) { - return new RenderSpace(renderInformation.getContentAreaSize() - .getWidth(), 0); - } else { - VConsole.error("Invalid child requested RenderSpace information"); - return null; - } - } - - public boolean hasChildComponent(Widget component) { - return component != null && (component == lo || component == footer); - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - if (!hasChildComponent(oldComponent)) { - throw new IllegalArgumentException( - "Old component is not inside this Container"); - } - remove(oldComponent); - if (oldComponent == lo) { - lo = (Container) newComponent; - add((Widget) lo, fieldContainer); - } else { - footer = (Container) newComponent; - add((Widget) footer, footerContainer); - } - - } - - public boolean requestLayout(Set child) { - - if (height != null && !"".equals(height) && width != null - && !"".equals(width)) { - /* - * If the height and width has been specified the child components - * cannot make the size of the layout change - */ - - return true; - } - - if (renderInformation.updateSize(getElement())) { - return false; - } else { - return true; - } - - } - - public void updateCaption(Paintable component, UIDL uidl) { - // NOP form don't render caption for neither field layout nor footer - // layout - } - - @Override - public void setHeight(String height) { - if (this.height.equals(height)) { - return; - } - - this.height = height; - super.setHeight(height); - - updateSize(); - } - - /** - * @return pixels consumed by decoration, captions, descrioptiosn etc.. In - * other words space, not used by the actual layout in form. - */ - private int getSpaceConsumedVertically() { - int offsetHeight2 = fieldSet.getOffsetHeight(); - int offsetHeight3 = fieldContainer.getOffsetHeight(); - int borderPadding = offsetHeight2 - offsetHeight3; - return borderPadding; - } - - @Override - public void setWidth(String width) { - if (borderPaddingHorizontal < 0) { - // measure excess size lazily after stylename setting, but before - // setting width - int ow = getOffsetWidth(); - int dow = desc.getOffsetWidth(); - borderPaddingHorizontal = ow - dow; - } - if (Util.equals(this.width, width)) { - return; - } - - this.width = width; - super.setWidth(width); - - updateSize(); - - if (!rendering && height.equals("")) { - // Width might affect height - Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this); - } - } - - public void onKeyDown(KeyDownEvent event) { - shortcutHandler.handleKeyboardEvent(Event.as(event.getNativeEvent())); - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import java.util.Set; + +import com.google.gwt.dom.client.Style.Display; +import com.google.gwt.event.dom.client.KeyDownEvent; +import com.google.gwt.event.dom.client.KeyDownHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.ComplexPanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.Container; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.RenderInformation; +import com.vaadin.terminal.gwt.client.RenderSpace; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.VErrorMessage; + +public class VForm extends ComplexPanel implements Container, KeyDownHandler { + + protected String id; + + private String height = ""; + + private String width = ""; + + public static final String CLASSNAME = "v-form"; + + private Container lo; + private Element legend = DOM.createLegend(); + private Element caption = DOM.createSpan(); + private Element errorIndicatorElement = DOM.createDiv(); + private Element desc = DOM.createDiv(); + private Icon icon; + private VErrorMessage errorMessage = new VErrorMessage(); + + private Element fieldContainer = DOM.createDiv(); + + private Element footerContainer = DOM.createDiv(); + + private Element fieldSet = DOM.createFieldSet(); + + private Container footer; + + private ApplicationConnection client; + + private RenderInformation renderInformation = new RenderInformation(); + + private int borderPaddingHorizontal = -1; + + private boolean rendering = false; + + ShortcutActionHandler shortcutHandler; + + private HandlerRegistration keyDownRegistration; + + public VForm() { + setElement(DOM.createDiv()); + getElement().appendChild(fieldSet); + setStyleName(CLASSNAME); + fieldSet.appendChild(legend); + legend.appendChild(caption); + errorIndicatorElement.setClassName("v-errorindicator"); + errorIndicatorElement.getStyle().setDisplay(Display.NONE); + errorIndicatorElement.setInnerText(" "); // needed for IE + desc.setClassName("v-form-description"); + fieldSet.appendChild(desc); // Adding description for initial padding + // measurements, removed later if no + // description is set + fieldSet.appendChild(fieldContainer); + errorMessage.setVisible(false); + errorMessage.setStyleName(CLASSNAME + "-errormessage"); + fieldSet.appendChild(errorMessage.getElement()); + fieldSet.appendChild(footerContainer); + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + rendering = true; + this.client = client; + id = uidl.getId(); + + if (client.updateComponent(this, uidl, false)) { + rendering = false; + return; + } + + boolean legendEmpty = true; + if (uidl.hasAttribute("caption")) { + caption.setInnerText(uidl.getStringAttribute("caption")); + legendEmpty = false; + } else { + caption.setInnerText(""); + } + if (uidl.hasAttribute("icon")) { + if (icon == null) { + icon = new Icon(client); + legend.insertFirst(icon.getElement()); + } + icon.setUri(uidl.getStringAttribute("icon")); + legendEmpty = false; + } else { + if (icon != null) { + legend.removeChild(icon.getElement()); + } + } + if (legendEmpty) { + addStyleDependentName("nocaption"); + } else { + removeStyleDependentName("nocaption"); + } + + if (uidl.hasAttribute("error")) { + final UIDL errorUidl = uidl.getErrors(); + errorMessage.updateFromUIDL(errorUidl); + errorMessage.setVisible(true); + + } else { + errorMessage.setVisible(false); + } + + if (uidl.hasAttribute("description")) { + desc.setInnerHTML(uidl.getStringAttribute("description")); + if (desc.getParentElement() == null) { + fieldSet.insertAfter(desc, legend); + } + } else { + desc.setInnerHTML(""); + if (desc.getParentElement() != null) { + fieldSet.removeChild(desc); + } + } + + updateSize(); + + // first render footer so it will be easier to handle relative height of + // main layout + if (uidl.getChildCount() > 1 + && !uidl.getChildUIDL(1).getTag().equals("actions")) { + // render footer + Container newFooter = (Container) client.getPaintable(uidl + .getChildUIDL(1)); + if (footer == null) { + add((Widget) newFooter, footerContainer); + footer = newFooter; + } else if (newFooter != footer) { + remove((Widget) footer); + client.unregisterPaintable(footer); + add((Widget) newFooter, footerContainer); + } + footer = newFooter; + footer.updateFromUIDL(uidl.getChildUIDL(1), client); + // needed for the main layout to know the space it has available + updateSize(); + } else { + if (footer != null) { + remove((Widget) footer); + client.unregisterPaintable(footer); + // needed for the main layout to know the space it has available + updateSize(); + } + } + + final UIDL layoutUidl = uidl.getChildUIDL(0); + Container newLo = (Container) client.getPaintable(layoutUidl); + if (lo == null) { + lo = newLo; + add((Widget) lo, fieldContainer); + } else if (lo != newLo) { + client.unregisterPaintable(lo); + remove((Widget) lo); + lo = newLo; + add((Widget) lo, fieldContainer); + } + lo.updateFromUIDL(layoutUidl, client); + + // also recalculates size of the footer if undefined size form - see + // #3710 + updateSize(); + client.runDescendentsLayout(this); + + // We may have actions attached + if (uidl.getChildCount() > 1) { + UIDL childUidl = uidl.getChildByTagName("actions"); + if (childUidl != null) { + if (shortcutHandler == null) { + shortcutHandler = new ShortcutActionHandler(id, client); + keyDownRegistration = addDomHandler(this, + KeyDownEvent.getType()); + } + shortcutHandler.updateActionMap(childUidl); + } + } else if (shortcutHandler != null) { + keyDownRegistration.removeHandler(); + shortcutHandler = null; + keyDownRegistration = null; + } + + rendering = false; + } + + public void updateSize() { + + renderInformation.updateSize(getElement()); + + renderInformation.setContentAreaHeight(renderInformation + .getRenderedSize().getHeight() - getSpaceConsumedVertically()); + if (BrowserInfo.get().isIE6()) { + getElement().getStyle().setProperty("overflow", "hidden"); + } + renderInformation.setContentAreaWidth(renderInformation + .getRenderedSize().getWidth() - borderPaddingHorizontal); + } + + public RenderSpace getAllocatedSpace(Widget child) { + if (child == lo) { + return renderInformation.getContentAreaSize(); + } else if (child == footer) { + return new RenderSpace(renderInformation.getContentAreaSize() + .getWidth(), 0); + } else { + VConsole.error("Invalid child requested RenderSpace information"); + return null; + } + } + + public boolean hasChildComponent(Widget component) { + return component != null && (component == lo || component == footer); + } + + public void replaceChildComponent(Widget oldComponent, Widget newComponent) { + if (!hasChildComponent(oldComponent)) { + throw new IllegalArgumentException( + "Old component is not inside this Container"); + } + remove(oldComponent); + if (oldComponent == lo) { + lo = (Container) newComponent; + add((Widget) lo, fieldContainer); + } else { + footer = (Container) newComponent; + add((Widget) footer, footerContainer); + } + + } + + public boolean requestLayout(Set child) { + + if (height != null && !"".equals(height) && width != null + && !"".equals(width)) { + /* + * If the height and width has been specified the child components + * cannot make the size of the layout change + */ + + return true; + } + + if (renderInformation.updateSize(getElement())) { + return false; + } else { + return true; + } + + } + + public void updateCaption(Paintable component, UIDL uidl) { + // NOP form don't render caption for neither field layout nor footer + // layout + } + + @Override + public void setHeight(String height) { + if (this.height.equals(height)) { + return; + } + + this.height = height; + super.setHeight(height); + + updateSize(); + } + + /** + * @return pixels consumed by decoration, captions, descrioptiosn etc.. In + * other words space, not used by the actual layout in form. + */ + private int getSpaceConsumedVertically() { + int offsetHeight2 = fieldSet.getOffsetHeight(); + int offsetHeight3 = fieldContainer.getOffsetHeight(); + int borderPadding = offsetHeight2 - offsetHeight3; + return borderPadding; + } + + @Override + public void setWidth(String width) { + if (borderPaddingHorizontal < 0) { + // measure excess size lazily after stylename setting, but before + // setting width + int ow = getOffsetWidth(); + int dow = desc.getOffsetWidth(); + borderPaddingHorizontal = ow - dow; + } + if (Util.equals(this.width, width)) { + return; + } + + this.width = width; + super.setWidth(width); + + updateSize(); + + if (!rendering && height.equals("")) { + // Width might affect height + Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this); + } + } + + public void onKeyDown(KeyDownEvent event) { + shortcutHandler.handleKeyboardEvent(Event.as(event.getNativeEvent())); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VLazyExecutor.java b/src/com/vaadin/terminal/gwt/client/ui/VLazyExecutor.java index 018df57327..aac8ca5ee7 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VLazyExecutor.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VLazyExecutor.java @@ -1,52 +1,52 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.core.client.Scheduler.ScheduledCommand; -import com.google.gwt.user.client.Timer; - -/** - * Executes the given command {@code delayMs} milliseconds after a call to - * {@link #trigger()}. Calling {@link #trigger()} again before the command has - * been executed causes the execution to be rescheduled to {@code delayMs} after - * the second call. - * - */ -public class VLazyExecutor { - - private Timer timer; - private int delayMs; - private ScheduledCommand cmd; - - /** - * @param delayMs - * Delay in milliseconds to wait before executing the command - * @param cmd - * The command to execute - */ - public VLazyExecutor(int delayMs, ScheduledCommand cmd) { - this.delayMs = delayMs; - this.cmd = cmd; - } - - /** - * Triggers execution of the command. Each call reschedules any existing - * execution to {@link #delayMs} milliseconds from that point in time. - */ - public void trigger() { - if (timer == null) { - timer = new Timer() { - @Override - public void run() { - timer = null; - cmd.execute(); - } - }; - } - // Schedule automatically cancels any old schedule - timer.schedule(delayMs); - - } - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.user.client.Timer; + +/** + * Executes the given command {@code delayMs} milliseconds after a call to + * {@link #trigger()}. Calling {@link #trigger()} again before the command has + * been executed causes the execution to be rescheduled to {@code delayMs} after + * the second call. + * + */ +public class VLazyExecutor { + + private Timer timer; + private int delayMs; + private ScheduledCommand cmd; + + /** + * @param delayMs + * Delay in milliseconds to wait before executing the command + * @param cmd + * The command to execute + */ + public VLazyExecutor(int delayMs, ScheduledCommand cmd) { + this.delayMs = delayMs; + this.cmd = cmd; + } + + /** + * Triggers execution of the command. Each call reschedules any existing + * execution to {@link #delayMs} milliseconds from that point in time. + */ + public void trigger() { + if (timer == null) { + timer = new Timer() { + @Override + public void run() { + timer = null; + cmd.execute(); + } + }; + } + // Schedule automatically cancels any old schedule + timer.schedule(delayMs); + + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNotification.java b/src/com/vaadin/terminal/gwt/client/ui/VNotification.java index 128e3bd597..27407c55aa 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VNotification.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VNotification.java @@ -1,417 +1,417 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.ArrayList; -import java.util.Date; -import java.util.EventObject; -import java.util.Iterator; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.event.dom.client.KeyCodes; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.Timer; -import com.google.gwt.user.client.ui.HTML; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; - -public class VNotification extends VOverlay { - - public static final int CENTERED = 1; - public static final int CENTERED_TOP = 2; - public static final int CENTERED_BOTTOM = 3; - public static final int TOP_LEFT = 4; - public static final int TOP_RIGHT = 5; - public static final int BOTTOM_LEFT = 6; - public static final int BOTTOM_RIGHT = 7; - - public static final int DELAY_FOREVER = -1; - public static final int DELAY_NONE = 0; - - private static final String STYLENAME = "v-Notification"; - private static final int mouseMoveThreshold = 7; - private static final int Z_INDEX_BASE = 20000; - public static final String STYLE_SYSTEM = "system"; - private static final int FADE_ANIMATION_INTERVAL = 50; // == 20 fps - - private int startOpacity = 90; - private int fadeMsec = 400; - private int delayMsec = 1000; - - private Timer fader; - private Timer delay; - - private int x = -1; - private int y = -1; - - private String temporaryStyle; - - private ArrayList listeners; - private static final int TOUCH_DEVICE_IDLE_DELAY = 1000; - - /** - * Default constructor. You should use GWT.create instead. - */ - public VNotification() { - setStyleName(STYLENAME); - sinkEvents(Event.ONCLICK); - DOM.setStyleAttribute(getElement(), "zIndex", "" + Z_INDEX_BASE); - } - - /** - * @deprecated Use static {@link #createNotification(int)} instead to enable - * GWT deferred binding. - * - * @param delayMsec - */ - @Deprecated - public VNotification(int delayMsec) { - this(); - this.delayMsec = delayMsec; - if (BrowserInfo.get().isTouchDevice()) { - new Timer() { - @Override - public void run() { - if (isAttached()) { - fade(); - } - } - }.schedule(delayMsec + TOUCH_DEVICE_IDLE_DELAY); - } - } - - /** - * @deprecated Use static {@link #createNotification(int, int, int)} instead - * to enable GWT deferred binding. - * - * @param delayMsec - * @param fadeMsec - * @param startOpacity - */ - @Deprecated - public VNotification(int delayMsec, int fadeMsec, int startOpacity) { - this(delayMsec); - this.fadeMsec = fadeMsec; - this.startOpacity = startOpacity; - } - - public void startDelay() { - DOM.removeEventPreview(this); - if (delayMsec > 0) { - if (delay == null) { - delay = new Timer() { - @Override - public void run() { - fade(); - } - }; - delay.schedule(delayMsec); - } - } else if (delayMsec == 0) { - fade(); - } - } - - @Override - public void show() { - show(CENTERED); - } - - public void show(String style) { - show(CENTERED, style); - } - - public void show(int position) { - show(position, null); - } - - public void show(Widget widget, int position, String style) { - setWidget(widget); - show(position, style); - } - - public void show(String html, int position, String style) { - setWidget(new HTML(html)); - show(position, style); - } - - public void show(int position, String style) { - setOpacity(getElement(), startOpacity); - if (style != null) { - temporaryStyle = style; - addStyleName(style); - addStyleDependentName(style); - } - super.show(); - setPosition(position); - } - - @Override - public void hide() { - DOM.removeEventPreview(this); - cancelDelay(); - cancelFade(); - if (temporaryStyle != null) { - removeStyleName(temporaryStyle); - removeStyleDependentName(temporaryStyle); - temporaryStyle = null; - } - super.hide(); - fireEvent(new HideEvent(this)); - } - - public void fade() { - DOM.removeEventPreview(this); - cancelDelay(); - if (fader == null) { - fader = new Timer() { - private final long start = new Date().getTime(); - - @Override - public void run() { - /* - * To make animation smooth, don't count that event happens - * on time. Reduce opacity according to the actual time - * spent instead of fixed decrement. - */ - long now = new Date().getTime(); - long timeEplaced = now - start; - float remainingFraction = 1 - timeEplaced - / (float) fadeMsec; - int opacity = (int) (startOpacity * remainingFraction); - if (opacity <= 0) { - cancel(); - hide(); - if (BrowserInfo.get().isOpera()) { - // tray notification on opera needs to explicitly - // define - // size, reset it - DOM.setStyleAttribute(getElement(), "width", ""); - DOM.setStyleAttribute(getElement(), "height", ""); - } - } else { - setOpacity(getElement(), opacity); - } - } - }; - fader.scheduleRepeating(FADE_ANIMATION_INTERVAL); - } - } - - public void setPosition(int position) { - final Element el = getElement(); - DOM.setStyleAttribute(el, "top", ""); - DOM.setStyleAttribute(el, "left", ""); - DOM.setStyleAttribute(el, "bottom", ""); - DOM.setStyleAttribute(el, "right", ""); - switch (position) { - case TOP_LEFT: - DOM.setStyleAttribute(el, "top", "0px"); - DOM.setStyleAttribute(el, "left", "0px"); - break; - case TOP_RIGHT: - DOM.setStyleAttribute(el, "top", "0px"); - DOM.setStyleAttribute(el, "right", "0px"); - break; - case BOTTOM_RIGHT: - DOM.setStyleAttribute(el, "position", "absolute"); - if (BrowserInfo.get().isOpera()) { - // tray notification on opera needs explicitly defined size - DOM.setStyleAttribute(el, "width", getOffsetWidth() + "px"); - DOM.setStyleAttribute(el, "height", getOffsetHeight() + "px"); - } - DOM.setStyleAttribute(el, "bottom", "0px"); - DOM.setStyleAttribute(el, "right", "0px"); - break; - case BOTTOM_LEFT: - DOM.setStyleAttribute(el, "bottom", "0px"); - DOM.setStyleAttribute(el, "left", "0px"); - break; - case CENTERED_TOP: - center(); - DOM.setStyleAttribute(el, "top", "0px"); - break; - case CENTERED_BOTTOM: - center(); - DOM.setStyleAttribute(el, "top", ""); - DOM.setStyleAttribute(el, "bottom", "0px"); - break; - default: - case CENTERED: - center(); - break; - } - } - - private void cancelFade() { - if (fader != null) { - fader.cancel(); - fader = null; - } - } - - private void cancelDelay() { - if (delay != null) { - delay.cancel(); - delay = null; - } - } - - private void setOpacity(Element el, int opacity) { - DOM.setStyleAttribute(el, "opacity", "" + (opacity / 100.0)); - if (BrowserInfo.get().isIE()) { - DOM.setStyleAttribute(el, "filter", "Alpha(opacity=" + opacity - + ")"); - } - } - - @Override - public void onBrowserEvent(Event event) { - DOM.removeEventPreview(this); - if (fader == null) { - fade(); - } - } - - @Override - public boolean onEventPreview(Event event) { - int type = DOM.eventGetType(event); - // "modal" - if (delayMsec == -1 || temporaryStyle == STYLE_SYSTEM) { - if (type == Event.ONCLICK) { - if (DOM.isOrHasChild(getElement(), DOM.eventGetTarget(event))) { - fade(); - return false; - } - } else if (type == Event.ONKEYDOWN - && event.getKeyCode() == KeyCodes.KEY_ESCAPE) { - fade(); - return false; - } - if (temporaryStyle == STYLE_SYSTEM) { - return true; - } else { - return false; - } - } - // default - switch (type) { - case Event.ONMOUSEMOVE: - - if (x < 0) { - x = DOM.eventGetClientX(event); - y = DOM.eventGetClientY(event); - } else if (Math.abs(DOM.eventGetClientX(event) - x) > mouseMoveThreshold - || Math.abs(DOM.eventGetClientY(event) - y) > mouseMoveThreshold) { - startDelay(); - } - break; - case Event.ONMOUSEDOWN: - case Event.ONMOUSEWHEEL: - case Event.ONSCROLL: - startDelay(); - break; - case Event.ONKEYDOWN: - if (event.getRepeat()) { - return true; - } - startDelay(); - break; - default: - break; - } - return true; - } - - public void addEventListener(EventListener listener) { - if (listeners == null) { - listeners = new ArrayList(); - } - listeners.add(listener); - } - - public void removeEventListener(EventListener listener) { - if (listeners == null) { - return; - } - listeners.remove(listener); - } - - private void fireEvent(HideEvent event) { - if (listeners != null) { - for (Iterator it = listeners.iterator(); it - .hasNext();) { - EventListener l = it.next(); - l.notificationHidden(event); - } - } - } - - public static void showNotification(ApplicationConnection client, - final UIDL notification) { - boolean onlyPlainText = notification - .hasAttribute(VView.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED); - String html = ""; - if (notification.hasAttribute("icon")) { - final String parsedUri = client.translateVaadinUri(notification - .getStringAttribute("icon")); - html += ""; - } - if (notification.hasAttribute("caption")) { - String caption = notification.getStringAttribute("caption"); - if (onlyPlainText) { - caption = Util.escapeHTML(caption); - caption = caption.replaceAll("\\n", "
"); - } - html += "

" + caption + "

"; - } - if (notification.hasAttribute("message")) { - String message = notification.getStringAttribute("message"); - if (onlyPlainText) { - message = Util.escapeHTML(message); - message = message.replaceAll("\\n", "
"); - } - html += "

" + message + "

"; - } - - final String style = notification.hasAttribute("style") ? notification - .getStringAttribute("style") : null; - final int position = notification.getIntAttribute("position"); - final int delay = notification.getIntAttribute("delay"); - createNotification(delay).show(html, position, style); - } - - public static VNotification createNotification(int delayMsec) { - final VNotification notification = GWT.create(VNotification.class); - notification.delayMsec = delayMsec; - if (BrowserInfo.get().isTouchDevice()) { - new Timer() { - @Override - public void run() { - if (notification.isAttached()) { - notification.fade(); - } - } - }.schedule(notification.delayMsec + TOUCH_DEVICE_IDLE_DELAY); - } - return notification; - } - - public class HideEvent extends EventObject { - - public HideEvent(Object source) { - super(source); - } - } - - public interface EventListener extends java.util.EventListener { - public void notificationHidden(HideEvent event); - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import java.util.ArrayList; +import java.util.Date; +import java.util.EventObject; +import java.util.Iterator; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; + +public class VNotification extends VOverlay { + + public static final int CENTERED = 1; + public static final int CENTERED_TOP = 2; + public static final int CENTERED_BOTTOM = 3; + public static final int TOP_LEFT = 4; + public static final int TOP_RIGHT = 5; + public static final int BOTTOM_LEFT = 6; + public static final int BOTTOM_RIGHT = 7; + + public static final int DELAY_FOREVER = -1; + public static final int DELAY_NONE = 0; + + private static final String STYLENAME = "v-Notification"; + private static final int mouseMoveThreshold = 7; + private static final int Z_INDEX_BASE = 20000; + public static final String STYLE_SYSTEM = "system"; + private static final int FADE_ANIMATION_INTERVAL = 50; // == 20 fps + + private int startOpacity = 90; + private int fadeMsec = 400; + private int delayMsec = 1000; + + private Timer fader; + private Timer delay; + + private int x = -1; + private int y = -1; + + private String temporaryStyle; + + private ArrayList listeners; + private static final int TOUCH_DEVICE_IDLE_DELAY = 1000; + + /** + * Default constructor. You should use GWT.create instead. + */ + public VNotification() { + setStyleName(STYLENAME); + sinkEvents(Event.ONCLICK); + DOM.setStyleAttribute(getElement(), "zIndex", "" + Z_INDEX_BASE); + } + + /** + * @deprecated Use static {@link #createNotification(int)} instead to enable + * GWT deferred binding. + * + * @param delayMsec + */ + @Deprecated + public VNotification(int delayMsec) { + this(); + this.delayMsec = delayMsec; + if (BrowserInfo.get().isTouchDevice()) { + new Timer() { + @Override + public void run() { + if (isAttached()) { + fade(); + } + } + }.schedule(delayMsec + TOUCH_DEVICE_IDLE_DELAY); + } + } + + /** + * @deprecated Use static {@link #createNotification(int, int, int)} instead + * to enable GWT deferred binding. + * + * @param delayMsec + * @param fadeMsec + * @param startOpacity + */ + @Deprecated + public VNotification(int delayMsec, int fadeMsec, int startOpacity) { + this(delayMsec); + this.fadeMsec = fadeMsec; + this.startOpacity = startOpacity; + } + + public void startDelay() { + DOM.removeEventPreview(this); + if (delayMsec > 0) { + if (delay == null) { + delay = new Timer() { + @Override + public void run() { + fade(); + } + }; + delay.schedule(delayMsec); + } + } else if (delayMsec == 0) { + fade(); + } + } + + @Override + public void show() { + show(CENTERED); + } + + public void show(String style) { + show(CENTERED, style); + } + + public void show(int position) { + show(position, null); + } + + public void show(Widget widget, int position, String style) { + setWidget(widget); + show(position, style); + } + + public void show(String html, int position, String style) { + setWidget(new HTML(html)); + show(position, style); + } + + public void show(int position, String style) { + setOpacity(getElement(), startOpacity); + if (style != null) { + temporaryStyle = style; + addStyleName(style); + addStyleDependentName(style); + } + super.show(); + setPosition(position); + } + + @Override + public void hide() { + DOM.removeEventPreview(this); + cancelDelay(); + cancelFade(); + if (temporaryStyle != null) { + removeStyleName(temporaryStyle); + removeStyleDependentName(temporaryStyle); + temporaryStyle = null; + } + super.hide(); + fireEvent(new HideEvent(this)); + } + + public void fade() { + DOM.removeEventPreview(this); + cancelDelay(); + if (fader == null) { + fader = new Timer() { + private final long start = new Date().getTime(); + + @Override + public void run() { + /* + * To make animation smooth, don't count that event happens + * on time. Reduce opacity according to the actual time + * spent instead of fixed decrement. + */ + long now = new Date().getTime(); + long timeEplaced = now - start; + float remainingFraction = 1 - timeEplaced + / (float) fadeMsec; + int opacity = (int) (startOpacity * remainingFraction); + if (opacity <= 0) { + cancel(); + hide(); + if (BrowserInfo.get().isOpera()) { + // tray notification on opera needs to explicitly + // define + // size, reset it + DOM.setStyleAttribute(getElement(), "width", ""); + DOM.setStyleAttribute(getElement(), "height", ""); + } + } else { + setOpacity(getElement(), opacity); + } + } + }; + fader.scheduleRepeating(FADE_ANIMATION_INTERVAL); + } + } + + public void setPosition(int position) { + final Element el = getElement(); + DOM.setStyleAttribute(el, "top", ""); + DOM.setStyleAttribute(el, "left", ""); + DOM.setStyleAttribute(el, "bottom", ""); + DOM.setStyleAttribute(el, "right", ""); + switch (position) { + case TOP_LEFT: + DOM.setStyleAttribute(el, "top", "0px"); + DOM.setStyleAttribute(el, "left", "0px"); + break; + case TOP_RIGHT: + DOM.setStyleAttribute(el, "top", "0px"); + DOM.setStyleAttribute(el, "right", "0px"); + break; + case BOTTOM_RIGHT: + DOM.setStyleAttribute(el, "position", "absolute"); + if (BrowserInfo.get().isOpera()) { + // tray notification on opera needs explicitly defined size + DOM.setStyleAttribute(el, "width", getOffsetWidth() + "px"); + DOM.setStyleAttribute(el, "height", getOffsetHeight() + "px"); + } + DOM.setStyleAttribute(el, "bottom", "0px"); + DOM.setStyleAttribute(el, "right", "0px"); + break; + case BOTTOM_LEFT: + DOM.setStyleAttribute(el, "bottom", "0px"); + DOM.setStyleAttribute(el, "left", "0px"); + break; + case CENTERED_TOP: + center(); + DOM.setStyleAttribute(el, "top", "0px"); + break; + case CENTERED_BOTTOM: + center(); + DOM.setStyleAttribute(el, "top", ""); + DOM.setStyleAttribute(el, "bottom", "0px"); + break; + default: + case CENTERED: + center(); + break; + } + } + + private void cancelFade() { + if (fader != null) { + fader.cancel(); + fader = null; + } + } + + private void cancelDelay() { + if (delay != null) { + delay.cancel(); + delay = null; + } + } + + private void setOpacity(Element el, int opacity) { + DOM.setStyleAttribute(el, "opacity", "" + (opacity / 100.0)); + if (BrowserInfo.get().isIE()) { + DOM.setStyleAttribute(el, "filter", "Alpha(opacity=" + opacity + + ")"); + } + } + + @Override + public void onBrowserEvent(Event event) { + DOM.removeEventPreview(this); + if (fader == null) { + fade(); + } + } + + @Override + public boolean onEventPreview(Event event) { + int type = DOM.eventGetType(event); + // "modal" + if (delayMsec == -1 || temporaryStyle == STYLE_SYSTEM) { + if (type == Event.ONCLICK) { + if (DOM.isOrHasChild(getElement(), DOM.eventGetTarget(event))) { + fade(); + return false; + } + } else if (type == Event.ONKEYDOWN + && event.getKeyCode() == KeyCodes.KEY_ESCAPE) { + fade(); + return false; + } + if (temporaryStyle == STYLE_SYSTEM) { + return true; + } else { + return false; + } + } + // default + switch (type) { + case Event.ONMOUSEMOVE: + + if (x < 0) { + x = DOM.eventGetClientX(event); + y = DOM.eventGetClientY(event); + } else if (Math.abs(DOM.eventGetClientX(event) - x) > mouseMoveThreshold + || Math.abs(DOM.eventGetClientY(event) - y) > mouseMoveThreshold) { + startDelay(); + } + break; + case Event.ONMOUSEDOWN: + case Event.ONMOUSEWHEEL: + case Event.ONSCROLL: + startDelay(); + break; + case Event.ONKEYDOWN: + if (event.getRepeat()) { + return true; + } + startDelay(); + break; + default: + break; + } + return true; + } + + public void addEventListener(EventListener listener) { + if (listeners == null) { + listeners = new ArrayList(); + } + listeners.add(listener); + } + + public void removeEventListener(EventListener listener) { + if (listeners == null) { + return; + } + listeners.remove(listener); + } + + private void fireEvent(HideEvent event) { + if (listeners != null) { + for (Iterator it = listeners.iterator(); it + .hasNext();) { + EventListener l = it.next(); + l.notificationHidden(event); + } + } + } + + public static void showNotification(ApplicationConnection client, + final UIDL notification) { + boolean onlyPlainText = notification + .hasAttribute(VView.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED); + String html = ""; + if (notification.hasAttribute("icon")) { + final String parsedUri = client.translateVaadinUri(notification + .getStringAttribute("icon")); + html += ""; + } + if (notification.hasAttribute("caption")) { + String caption = notification.getStringAttribute("caption"); + if (onlyPlainText) { + caption = Util.escapeHTML(caption); + caption = caption.replaceAll("\\n", "
"); + } + html += "

" + caption + "

"; + } + if (notification.hasAttribute("message")) { + String message = notification.getStringAttribute("message"); + if (onlyPlainText) { + message = Util.escapeHTML(message); + message = message.replaceAll("\\n", "
"); + } + html += "

" + message + "

"; + } + + final String style = notification.hasAttribute("style") ? notification + .getStringAttribute("style") : null; + final int position = notification.getIntAttribute("position"); + final int delay = notification.getIntAttribute("delay"); + createNotification(delay).show(html, position, style); + } + + public static VNotification createNotification(int delayMsec) { + final VNotification notification = GWT.create(VNotification.class); + notification.delayMsec = delayMsec; + if (BrowserInfo.get().isTouchDevice()) { + new Timer() { + @Override + public void run() { + if (notification.isAttached()) { + notification.fade(); + } + } + }.schedule(notification.delayMsec + TOUCH_DEVICE_IDLE_DELAY); + } + return notification; + } + + public class HideEvent extends EventObject { + + public HideEvent(Object source) { + super(source); + } + } + + public interface EventListener extends java.util.EventListener { + public void notificationHidden(HideEvent event); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java index 1b6c681773..662f195fcd 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java @@ -1,235 +1,235 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.FocusEvent; -import com.google.gwt.event.dom.client.FocusHandler; -import com.google.gwt.event.dom.client.LoadEvent; -import com.google.gwt.event.dom.client.LoadHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.ui.CheckBox; -import com.google.gwt.user.client.ui.FocusWidget; -import com.google.gwt.user.client.ui.Focusable; -import com.google.gwt.user.client.ui.Panel; -import com.google.gwt.user.client.ui.RadioButton; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; - -public class VOptionGroup extends VOptionGroupBase implements FocusHandler, - BlurHandler { - - public static final String HTML_CONTENT_ALLOWED = "usehtml"; - - public static final String CLASSNAME = "v-select-optiongroup"; - - private final Panel panel; - - private final Map optionsToKeys; - - private boolean sendFocusEvents = false; - private boolean sendBlurEvents = false; - private List focusHandlers = null; - private List blurHandlers = null; - - private final LoadHandler iconLoadHandler = new LoadHandler() { - public void onLoad(LoadEvent event) { - if (BrowserInfo.get().isIE6()) { - Util.doIE6PngFix((Element) Element.as(event.getNativeEvent() - .getEventTarget())); - } - Util.notifyParentOfSizeChange(VOptionGroup.this, true); - } - }; - - /** - * used to check whether a blur really was a blur of the complete - * optiongroup: if a control inside this optiongroup gains focus right after - * blur of another control inside this optiongroup (meaning: if onFocus - * fires after onBlur has fired), the blur and focus won't be sent to the - * server side as only a focus change inside this optiongroup occured - */ - private boolean blurOccured = false; - - private boolean htmlContentAllowed = false; - - public VOptionGroup() { - super(CLASSNAME); - panel = (Panel) optionsContainer; - optionsToKeys = new HashMap(); - } - - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - htmlContentAllowed = uidl.hasAttribute(HTML_CONTENT_ALLOWED); - - super.updateFromUIDL(uidl, client); - - sendFocusEvents = client.hasEventListeners(this, EventId.FOCUS); - sendBlurEvents = client.hasEventListeners(this, EventId.BLUR); - - if (focusHandlers != null) { - for (HandlerRegistration reg : focusHandlers) { - reg.removeHandler(); - } - focusHandlers.clear(); - focusHandlers = null; - - for (HandlerRegistration reg : blurHandlers) { - reg.removeHandler(); - } - blurHandlers.clear(); - blurHandlers = null; - } - - if (sendFocusEvents || sendBlurEvents) { - focusHandlers = new ArrayList(); - blurHandlers = new ArrayList(); - - // add focus and blur handlers to checkboxes / radio buttons - for (Widget wid : panel) { - if (wid instanceof CheckBox) { - focusHandlers.add(((CheckBox) wid).addFocusHandler(this)); - blurHandlers.add(((CheckBox) wid).addBlurHandler(this)); - } - } - } - } - - /* - * Return true if no elements were changed, false otherwise. - */ - @Override - protected void buildOptions(UIDL uidl) { - panel.clear(); - for (final Iterator it = uidl.getChildIterator(); it.hasNext();) { - final UIDL opUidl = (UIDL) it.next(); - CheckBox op; - - String itemHtml = opUidl.getStringAttribute("caption"); - if (!htmlContentAllowed) { - itemHtml = Util.escapeHTML(itemHtml); - } - - String icon = opUidl.getStringAttribute("icon"); - if (icon != null && icon.length() != 0) { - String iconUrl = client.translateVaadinUri(icon); - itemHtml = "\"\"" + itemHtml; - } - - if (isMultiselect()) { - op = new VCheckBox(); - op.setHTML(itemHtml); - } else { - op = new RadioButton(id, itemHtml, true); - op.setStyleName("v-radiobutton"); - } - - if (icon != null && icon.length() != 0) { - Util.sinkOnloadForImages(op.getElement()); - op.addHandler(iconLoadHandler, LoadEvent.getType()); - } - - op.addStyleName(CLASSNAME_OPTION); - op.setValue(opUidl.getBooleanAttribute("selected")); - boolean enabled = !opUidl.getBooleanAttribute("disabled") - && !isReadonly() && !isDisabled(); - op.setEnabled(enabled); - setStyleName(op.getElement(), - ApplicationConnection.DISABLED_CLASSNAME, !enabled); - op.addClickHandler(this); - optionsToKeys.put(op, opUidl.getStringAttribute("key")); - panel.add(op); - } - } - - @Override - protected String[] getSelectedItems() { - return selectedKeys.toArray(new String[selectedKeys.size()]); - } - - @Override - public void onClick(ClickEvent event) { - super.onClick(event); - if (event.getSource() instanceof CheckBox) { - final boolean selected = ((CheckBox) event.getSource()).getValue(); - final String key = optionsToKeys.get(event.getSource()); - if (!isMultiselect()) { - selectedKeys.clear(); - } - if (selected) { - selectedKeys.add(key); - } else { - selectedKeys.remove(key); - } - client.updateVariable(id, "selected", getSelectedItems(), - isImmediate()); - } - } - - @Override - protected void setTabIndex(int tabIndex) { - for (Iterator iterator = panel.iterator(); iterator.hasNext();) { - FocusWidget widget = (FocusWidget) iterator.next(); - widget.setTabIndex(tabIndex); - } - } - - public void focus() { - Iterator iterator = panel.iterator(); - if (iterator.hasNext()) { - ((Focusable) iterator.next()).setFocus(true); - } - } - - public void onFocus(FocusEvent arg0) { - if (!blurOccured) { - // no blur occured before this focus event - // panel was blurred => fire the event to the server side if - // requested by server side - if (sendFocusEvents) { - client.updateVariable(id, EventId.FOCUS, "", true); - } - } else { - // blur occured before this focus event - // another control inside the panel (checkbox / radio box) was - // blurred => do not fire the focus and set blurOccured to false, so - // blur will not be fired, too - blurOccured = false; - } - } - - public void onBlur(BlurEvent arg0) { - blurOccured = true; - if (sendBlurEvents) { - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - // check whether blurOccured still is true and then send the - // event out to the server - if (blurOccured) { - client.updateVariable(id, EventId.BLUR, "", true); - blurOccured = false; - } - } - }); - } - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.event.dom.client.BlurEvent; +import com.google.gwt.event.dom.client.BlurHandler; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.FocusEvent; +import com.google.gwt.event.dom.client.FocusHandler; +import com.google.gwt.event.dom.client.LoadEvent; +import com.google.gwt.event.dom.client.LoadHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.CheckBox; +import com.google.gwt.user.client.ui.FocusWidget; +import com.google.gwt.user.client.ui.Focusable; +import com.google.gwt.user.client.ui.Panel; +import com.google.gwt.user.client.ui.RadioButton; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.EventId; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; + +public class VOptionGroup extends VOptionGroupBase implements FocusHandler, + BlurHandler { + + public static final String HTML_CONTENT_ALLOWED = "usehtml"; + + public static final String CLASSNAME = "v-select-optiongroup"; + + private final Panel panel; + + private final Map optionsToKeys; + + private boolean sendFocusEvents = false; + private boolean sendBlurEvents = false; + private List focusHandlers = null; + private List blurHandlers = null; + + private final LoadHandler iconLoadHandler = new LoadHandler() { + public void onLoad(LoadEvent event) { + if (BrowserInfo.get().isIE6()) { + Util.doIE6PngFix((Element) Element.as(event.getNativeEvent() + .getEventTarget())); + } + Util.notifyParentOfSizeChange(VOptionGroup.this, true); + } + }; + + /** + * used to check whether a blur really was a blur of the complete + * optiongroup: if a control inside this optiongroup gains focus right after + * blur of another control inside this optiongroup (meaning: if onFocus + * fires after onBlur has fired), the blur and focus won't be sent to the + * server side as only a focus change inside this optiongroup occured + */ + private boolean blurOccured = false; + + private boolean htmlContentAllowed = false; + + public VOptionGroup() { + super(CLASSNAME); + panel = (Panel) optionsContainer; + optionsToKeys = new HashMap(); + } + + @Override + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + htmlContentAllowed = uidl.hasAttribute(HTML_CONTENT_ALLOWED); + + super.updateFromUIDL(uidl, client); + + sendFocusEvents = client.hasEventListeners(this, EventId.FOCUS); + sendBlurEvents = client.hasEventListeners(this, EventId.BLUR); + + if (focusHandlers != null) { + for (HandlerRegistration reg : focusHandlers) { + reg.removeHandler(); + } + focusHandlers.clear(); + focusHandlers = null; + + for (HandlerRegistration reg : blurHandlers) { + reg.removeHandler(); + } + blurHandlers.clear(); + blurHandlers = null; + } + + if (sendFocusEvents || sendBlurEvents) { + focusHandlers = new ArrayList(); + blurHandlers = new ArrayList(); + + // add focus and blur handlers to checkboxes / radio buttons + for (Widget wid : panel) { + if (wid instanceof CheckBox) { + focusHandlers.add(((CheckBox) wid).addFocusHandler(this)); + blurHandlers.add(((CheckBox) wid).addBlurHandler(this)); + } + } + } + } + + /* + * Return true if no elements were changed, false otherwise. + */ + @Override + protected void buildOptions(UIDL uidl) { + panel.clear(); + for (final Iterator it = uidl.getChildIterator(); it.hasNext();) { + final UIDL opUidl = (UIDL) it.next(); + CheckBox op; + + String itemHtml = opUidl.getStringAttribute("caption"); + if (!htmlContentAllowed) { + itemHtml = Util.escapeHTML(itemHtml); + } + + String icon = opUidl.getStringAttribute("icon"); + if (icon != null && icon.length() != 0) { + String iconUrl = client.translateVaadinUri(icon); + itemHtml = "\"\"" + itemHtml; + } + + if (isMultiselect()) { + op = new VCheckBox(); + op.setHTML(itemHtml); + } else { + op = new RadioButton(id, itemHtml, true); + op.setStyleName("v-radiobutton"); + } + + if (icon != null && icon.length() != 0) { + Util.sinkOnloadForImages(op.getElement()); + op.addHandler(iconLoadHandler, LoadEvent.getType()); + } + + op.addStyleName(CLASSNAME_OPTION); + op.setValue(opUidl.getBooleanAttribute("selected")); + boolean enabled = !opUidl.getBooleanAttribute("disabled") + && !isReadonly() && !isDisabled(); + op.setEnabled(enabled); + setStyleName(op.getElement(), + ApplicationConnection.DISABLED_CLASSNAME, !enabled); + op.addClickHandler(this); + optionsToKeys.put(op, opUidl.getStringAttribute("key")); + panel.add(op); + } + } + + @Override + protected String[] getSelectedItems() { + return selectedKeys.toArray(new String[selectedKeys.size()]); + } + + @Override + public void onClick(ClickEvent event) { + super.onClick(event); + if (event.getSource() instanceof CheckBox) { + final boolean selected = ((CheckBox) event.getSource()).getValue(); + final String key = optionsToKeys.get(event.getSource()); + if (!isMultiselect()) { + selectedKeys.clear(); + } + if (selected) { + selectedKeys.add(key); + } else { + selectedKeys.remove(key); + } + client.updateVariable(id, "selected", getSelectedItems(), + isImmediate()); + } + } + + @Override + protected void setTabIndex(int tabIndex) { + for (Iterator iterator = panel.iterator(); iterator.hasNext();) { + FocusWidget widget = (FocusWidget) iterator.next(); + widget.setTabIndex(tabIndex); + } + } + + public void focus() { + Iterator iterator = panel.iterator(); + if (iterator.hasNext()) { + ((Focusable) iterator.next()).setFocus(true); + } + } + + public void onFocus(FocusEvent arg0) { + if (!blurOccured) { + // no blur occured before this focus event + // panel was blurred => fire the event to the server side if + // requested by server side + if (sendFocusEvents) { + client.updateVariable(id, EventId.FOCUS, "", true); + } + } else { + // blur occured before this focus event + // another control inside the panel (checkbox / radio box) was + // blurred => do not fire the focus and set blurOccured to false, so + // blur will not be fired, too + blurOccured = false; + } + } + + public void onBlur(BlurEvent arg0) { + blurOccured = true; + if (sendBlurEvents) { + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + // check whether blurOccured still is true and then send the + // event out to the server + if (blurOccured) { + client.updateVariable(id, EventId.BLUR, "", true); + blurOccured = false; + } + } + }); + } + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java index 8be0aff3f0..50a9f8cb98 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java @@ -1,227 +1,227 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.Set; - -import com.google.gwt.event.dom.client.ChangeEvent; -import com.google.gwt.event.dom.client.ChangeHandler; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.KeyCodes; -import com.google.gwt.event.dom.client.KeyPressEvent; -import com.google.gwt.event.dom.client.KeyPressHandler; -import com.google.gwt.user.client.ui.Composite; -import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.Panel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Focusable; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; - -abstract class VOptionGroupBase extends Composite implements Paintable, Field, - ClickHandler, ChangeHandler, KeyPressHandler, Focusable { - - public static final String CLASSNAME_OPTION = "v-select-option"; - - protected ApplicationConnection client; - - protected String id; - - protected Set selectedKeys; - - private boolean immediate; - - private boolean multiselect; - - private boolean disabled; - - private boolean readonly; - - private int cols = 0; - - private int rows = 0; - - private boolean nullSelectionAllowed = true; - - private boolean nullSelectionItemAvailable = false; - - /** - * Widget holding the different options (e.g. ListBox or Panel for radio - * buttons) (optional, fallbacks to container Panel) - */ - protected Widget optionsContainer; - - /** - * Panel containing the component - */ - private final Panel container; - - private VTextField newItemField; - - private VNativeButton newItemButton; - - public VOptionGroupBase(String classname) { - container = new FlowPanel(); - initWidget(container); - optionsContainer = container; - container.setStyleName(classname); - immediate = false; - multiselect = false; - } - - /* - * Call this if you wish to specify your own container for the option - * elements (e.g. SELECT) - */ - public VOptionGroupBase(Widget w, String classname) { - this(classname); - optionsContainer = w; - container.add(optionsContainer); - } - - protected boolean isImmediate() { - return immediate; - } - - protected boolean isMultiselect() { - return multiselect; - } - - protected boolean isDisabled() { - return disabled; - } - - protected boolean isReadonly() { - return readonly; - } - - protected boolean isNullSelectionAllowed() { - return nullSelectionAllowed; - } - - protected boolean isNullSelectionItemAvailable() { - return nullSelectionItemAvailable; - } - - /** - * @return "cols" specified in uidl, 0 if not specified - */ - protected int getColumns() { - return cols; - } - - /** - * @return "rows" specified in uidl, 0 if not specified - */ - - protected int getRows() { - return rows; - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - this.client = client; - id = uidl.getId(); - - if (client.updateComponent(this, uidl, true)) { - return; - } - - selectedKeys = uidl.getStringArrayVariableAsSet("selected"); - - readonly = uidl.getBooleanAttribute("readonly"); - disabled = uidl.getBooleanAttribute("disabled"); - multiselect = "multi".equals(uidl.getStringAttribute("selectmode")); - immediate = uidl.getBooleanAttribute("immediate"); - nullSelectionAllowed = uidl.getBooleanAttribute("nullselect"); - nullSelectionItemAvailable = uidl.getBooleanAttribute("nullselectitem"); - - if (uidl.hasAttribute("cols")) { - cols = uidl.getIntAttribute("cols"); - } - if (uidl.hasAttribute("rows")) { - rows = uidl.getIntAttribute("rows"); - } - - final UIDL ops = uidl.getChildUIDL(0); - - if (getColumns() > 0) { - container.setWidth(getColumns() + "em"); - if (container != optionsContainer) { - optionsContainer.setWidth("100%"); - } - } - - buildOptions(ops); - - if (uidl.getBooleanAttribute("allownewitem")) { - if (newItemField == null) { - newItemButton = new VNativeButton(); - newItemButton.setText("+"); - newItemButton.addClickHandler(this); - newItemField = new VTextField(); - newItemField.addKeyPressHandler(this); - } - newItemField.setEnabled(!disabled && !readonly); - newItemButton.setEnabled(!disabled && !readonly); - - if (newItemField == null || newItemField.getParent() != container) { - container.add(newItemField); - container.add(newItemButton); - final int w = container.getOffsetWidth() - - newItemButton.getOffsetWidth(); - newItemField.setWidth(Math.max(w, 0) + "px"); - } - } else if (newItemField != null) { - container.remove(newItemField); - container.remove(newItemButton); - } - - setTabIndex(uidl.hasAttribute("tabindex") ? uidl - .getIntAttribute("tabindex") : 0); - - } - - abstract protected void setTabIndex(int tabIndex); - - public void onClick(ClickEvent event) { - if (event.getSource() == newItemButton - && !newItemField.getText().equals("")) { - client.updateVariable(id, "newitem", newItemField.getText(), true); - newItemField.setText(""); - } - } - - public void onChange(ChangeEvent event) { - if (multiselect) { - client.updateVariable(id, "selected", getSelectedItems(), immediate); - } else { - client.updateVariable(id, "selected", new String[] { "" - + getSelectedItem() }, immediate); - } - } - - public void onKeyPress(KeyPressEvent event) { - if (event.getSource() == newItemField - && event.getCharCode() == KeyCodes.KEY_ENTER) { - newItemButton.click(); - } - } - - protected abstract void buildOptions(UIDL uidl); - - protected abstract String[] getSelectedItems(); - - protected String getSelectedItem() { - final String[] sel = getSelectedItems(); - if (sel.length > 0) { - return sel[0]; - } else { - return null; - } - } - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import java.util.Set; + +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.ChangeHandler; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.event.dom.client.KeyPressEvent; +import com.google.gwt.event.dom.client.KeyPressHandler; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Panel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Focusable; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; + +abstract class VOptionGroupBase extends Composite implements Paintable, Field, + ClickHandler, ChangeHandler, KeyPressHandler, Focusable { + + public static final String CLASSNAME_OPTION = "v-select-option"; + + protected ApplicationConnection client; + + protected String id; + + protected Set selectedKeys; + + private boolean immediate; + + private boolean multiselect; + + private boolean disabled; + + private boolean readonly; + + private int cols = 0; + + private int rows = 0; + + private boolean nullSelectionAllowed = true; + + private boolean nullSelectionItemAvailable = false; + + /** + * Widget holding the different options (e.g. ListBox or Panel for radio + * buttons) (optional, fallbacks to container Panel) + */ + protected Widget optionsContainer; + + /** + * Panel containing the component + */ + private final Panel container; + + private VTextField newItemField; + + private VNativeButton newItemButton; + + public VOptionGroupBase(String classname) { + container = new FlowPanel(); + initWidget(container); + optionsContainer = container; + container.setStyleName(classname); + immediate = false; + multiselect = false; + } + + /* + * Call this if you wish to specify your own container for the option + * elements (e.g. SELECT) + */ + public VOptionGroupBase(Widget w, String classname) { + this(classname); + optionsContainer = w; + container.add(optionsContainer); + } + + protected boolean isImmediate() { + return immediate; + } + + protected boolean isMultiselect() { + return multiselect; + } + + protected boolean isDisabled() { + return disabled; + } + + protected boolean isReadonly() { + return readonly; + } + + protected boolean isNullSelectionAllowed() { + return nullSelectionAllowed; + } + + protected boolean isNullSelectionItemAvailable() { + return nullSelectionItemAvailable; + } + + /** + * @return "cols" specified in uidl, 0 if not specified + */ + protected int getColumns() { + return cols; + } + + /** + * @return "rows" specified in uidl, 0 if not specified + */ + + protected int getRows() { + return rows; + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + this.client = client; + id = uidl.getId(); + + if (client.updateComponent(this, uidl, true)) { + return; + } + + selectedKeys = uidl.getStringArrayVariableAsSet("selected"); + + readonly = uidl.getBooleanAttribute("readonly"); + disabled = uidl.getBooleanAttribute("disabled"); + multiselect = "multi".equals(uidl.getStringAttribute("selectmode")); + immediate = uidl.getBooleanAttribute("immediate"); + nullSelectionAllowed = uidl.getBooleanAttribute("nullselect"); + nullSelectionItemAvailable = uidl.getBooleanAttribute("nullselectitem"); + + if (uidl.hasAttribute("cols")) { + cols = uidl.getIntAttribute("cols"); + } + if (uidl.hasAttribute("rows")) { + rows = uidl.getIntAttribute("rows"); + } + + final UIDL ops = uidl.getChildUIDL(0); + + if (getColumns() > 0) { + container.setWidth(getColumns() + "em"); + if (container != optionsContainer) { + optionsContainer.setWidth("100%"); + } + } + + buildOptions(ops); + + if (uidl.getBooleanAttribute("allownewitem")) { + if (newItemField == null) { + newItemButton = new VNativeButton(); + newItemButton.setText("+"); + newItemButton.addClickHandler(this); + newItemField = new VTextField(); + newItemField.addKeyPressHandler(this); + } + newItemField.setEnabled(!disabled && !readonly); + newItemButton.setEnabled(!disabled && !readonly); + + if (newItemField == null || newItemField.getParent() != container) { + container.add(newItemField); + container.add(newItemButton); + final int w = container.getOffsetWidth() + - newItemButton.getOffsetWidth(); + newItemField.setWidth(Math.max(w, 0) + "px"); + } + } else if (newItemField != null) { + container.remove(newItemField); + container.remove(newItemButton); + } + + setTabIndex(uidl.hasAttribute("tabindex") ? uidl + .getIntAttribute("tabindex") : 0); + + } + + abstract protected void setTabIndex(int tabIndex); + + public void onClick(ClickEvent event) { + if (event.getSource() == newItemButton + && !newItemField.getText().equals("")) { + client.updateVariable(id, "newitem", newItemField.getText(), true); + newItemField.setText(""); + } + } + + public void onChange(ChangeEvent event) { + if (multiselect) { + client.updateVariable(id, "selected", getSelectedItems(), immediate); + } else { + client.updateVariable(id, "selected", new String[] { "" + + getSelectedItem() }, immediate); + } + } + + public void onKeyPress(KeyPressEvent event) { + if (event.getSource() == newItemField + && event.getCharCode() == KeyCodes.KEY_ENTER) { + newItemButton.click(); + } + } + + protected abstract void buildOptions(UIDL uidl); + + protected abstract String[] getSelectedItems(); + + protected String getSelectedItem() { + final String[] sel = getSelectedItems(); + if (sel.length > 0) { + return sel[0]; + } else { + return null; + } + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java index 84a22bc272..ecdb171ec4 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java @@ -885,7 +885,7 @@ public class VOrderedLayout extends CellBasedLayout { protected void updateAlignmentsAndExpandRatios(UIDL uidl, ArrayList renderedWidgets) { - /* + /* */ alignments = uidl.getMapAttribute("alignments"); diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPasswordField.java b/src/com/vaadin/terminal/gwt/client/ui/VPasswordField.java index 945f0d85e6..5182457067 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VPasswordField.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VPasswordField.java @@ -1,21 +1,21 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.user.client.DOM; - -/** - * This class represents a password field. - * - * @author Vaadin Ltd. - * - */ -public class VPasswordField extends VTextField { - - public VPasswordField() { - super(DOM.createInputPassword()); - } - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import com.google.gwt.user.client.DOM; + +/** + * This class represents a password field. + * + * @author Vaadin Ltd. + * + */ +public class VPasswordField extends VTextField { + + public VPasswordField() { + super(DOM.createInputPassword()); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java index 549248aab3..8bf2f6bfbf 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java @@ -1,482 +1,482 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.Date; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.DomEvent; -import com.google.gwt.event.dom.client.KeyCodes; -import com.google.gwt.event.logical.shared.CloseEvent; -import com.google.gwt.event.logical.shared.CloseHandler; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.Timer; -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.ui.Button; -import com.google.gwt.user.client.ui.PopupPanel; -import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.DateTimeService; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener; - -/** - * Represents a date selection component with a text field and a popup date - * selector. - * - * Note: To change the keyboard assignments used in the popup dialog you - * should extend com.vaadin.terminal.gwt.client.ui.VCalendarPanel - * and then pass set it by calling the - * setCalendarPanel(VCalendarPanel panel) method. - * - */ -public class VPopupCalendar extends VTextualDate implements Paintable, Field, - ClickHandler, CloseHandler, SubPartAware { - - private static final String POPUP_PRIMARY_STYLE_NAME = VDateField.CLASSNAME - + "-popup"; - - private final Button calendarToggle; - - private VCalendarPanel calendar; - - private final VOverlay popup; - private boolean open = false; - private boolean parsable = true; - - public VPopupCalendar() { - super(); - - calendarToggle = new Button(); - calendarToggle.setStyleName(CLASSNAME + "-button"); - calendarToggle.setText(""); - calendarToggle.addClickHandler(this); - // -2 instead of -1 to avoid FocusWidget.onAttach to reset it - calendarToggle.getElement().setTabIndex(-2); - add(calendarToggle); - - calendar = GWT.create(VCalendarPanel.class); - calendar.setFocusOutListener(new FocusOutListener() { - public boolean onFocusOut(DomEvent event) { - event.preventDefault(); - closeCalendarPanel(); - return true; - } - }); - - calendar.setSubmitListener(new SubmitListener() { - public void onSubmit() { - // Update internal value and send valuechange event if immediate - updateValue(calendar.getDate()); - - // Update text field (a must when not immediate). - buildDate(true); - - closeCalendarPanel(); - } - - public void onCancel() { - closeCalendarPanel(); - } - }); - - popup = new VOverlay(true, true, true); - popup.setStyleName(POPUP_PRIMARY_STYLE_NAME); - popup.setWidget(calendar); - popup.addCloseHandler(this); - - DOM.setElementProperty(calendar.getElement(), "id", - "PID_VAADIN_POPUPCAL"); - - sinkEvents(Event.ONKEYDOWN); - - } - - @SuppressWarnings("deprecation") - private void updateValue(Date newDate) { - Date currentDate = getCurrentDate(); - if (currentDate == null || newDate.getTime() != currentDate.getTime()) { - setCurrentDate((Date) newDate.clone()); - getClient().updateVariable(getId(), "year", - newDate.getYear() + 1900, false); - if (getCurrentResolution() > VDateField.RESOLUTION_YEAR) { - getClient().updateVariable(getId(), "month", - newDate.getMonth() + 1, false); - if (getCurrentResolution() > RESOLUTION_MONTH) { - getClient().updateVariable(getId(), "day", - newDate.getDate(), false); - if (getCurrentResolution() > RESOLUTION_DAY) { - getClient().updateVariable(getId(), "hour", - newDate.getHours(), false); - if (getCurrentResolution() > RESOLUTION_HOUR) { - getClient().updateVariable(getId(), "min", - newDate.getMinutes(), false); - if (getCurrentResolution() > RESOLUTION_MIN) { - getClient().updateVariable(getId(), "sec", - newDate.getSeconds(), false); - if (getCurrentResolution() == RESOLUTION_MSEC) { - getClient().updateVariable( - getId(), - "msec", - DateTimeService - .getMilliseconds(newDate), - false); - } - } - } - } - } - } - if (isImmediate()) { - getClient().sendPendingVariableChanges(); - } - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.gwt.client.ui.VTextualDate#updateFromUIDL(com.vaadin - * .terminal.gwt.client.UIDL, - * com.vaadin.terminal.gwt.client.ApplicationConnection) - */ - @Override - @SuppressWarnings("deprecation") - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - boolean lastReadOnlyState = readonly; - boolean lastEnabledState = isEnabled(); - - parsable = uidl.getBooleanAttribute("parsable"); - - super.updateFromUIDL(uidl, client); - - String popupStyleNames = ApplicationConnection.getStyleName( - POPUP_PRIMARY_STYLE_NAME, uidl, false); - popupStyleNames += " " + VDateField.CLASSNAME + "-" - + resolutionToString(currentResolution); - popup.setStyleName(popupStyleNames); - - calendar.setDateTimeService(getDateTimeService()); - calendar.setShowISOWeekNumbers(isShowISOWeekNumbers()); - if (calendar.getResolution() != currentResolution) { - calendar.setResolution(currentResolution); - if (calendar.getDate() != null) { - calendar.setDate((Date) getCurrentDate().clone()); - // force re-render when changing resolution only - calendar.renderCalendar(); - } - } - calendarToggle.setEnabled(enabled); - - if (currentResolution <= RESOLUTION_MONTH) { - calendar.setFocusChangeListener(new FocusChangeListener() { - public void focusChanged(Date date) { - updateValue(date); - buildDate(); - Date date2 = calendar.getDate(); - date2.setYear(date.getYear()); - date2.setMonth(date.getMonth()); - } - }); - } else { - calendar.setFocusChangeListener(null); - } - - if (currentResolution > RESOLUTION_DAY) { - calendar.setTimeChangeListener(new TimeChangeListener() { - public void changed(int hour, int min, int sec, int msec) { - Date d = getDate(); - if (d == null) { - // date currently null, use the value from calendarPanel - // (~ client time at the init of the widget) - d = (Date) calendar.getDate().clone(); - } - d.setHours(hour); - d.setMinutes(min); - d.setSeconds(sec); - DateTimeService.setMilliseconds(d, msec); - - // Always update time changes to the server - updateValue(d); - - // Update text field - buildDate(); - } - }); - } - - if (readonly) { - calendarToggle.addStyleName(CLASSNAME + "-button-readonly"); - } else { - calendarToggle.removeStyleName(CLASSNAME + "-button-readonly"); - } - - if (lastReadOnlyState != readonly || lastEnabledState != isEnabled()) { - // Enabled or readonly state changed. Differences in theming might - // affect the width (for instance if the popup button is hidden) so - // we have to recalculate the width (IF the width of the field is - // fixed) - updateWidth(); - } - - calendarToggle.setEnabled(true); - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.user.client.ui.UIObject#setStyleName(java.lang.String) - */ - @Override - public void setStyleName(String style) { - // make sure the style is there before size calculation - super.setStyleName(style + " " + CLASSNAME + "-popupcalendar"); - } - - /** - * Opens the calendar panel popup - */ - public void openCalendarPanel() { - - if (!open && !readonly) { - open = true; - - if (getCurrentDate() != null) { - calendar.setDate((Date) getCurrentDate().clone()); - } else { - calendar.setDate(new Date()); - } - - // clear previous values - popup.setWidth(""); - popup.setHeight(""); - popup.setPopupPositionAndShow(new PositionCallback() { - 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(); - - // 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 > 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 - popup.setWidth(w + "px"); - popup.setHeight(h + "px"); - - popup.setPopupPosition(l, - t + calendarToggle.getOffsetHeight() + 2); - - /* - * We have to wait a while before focusing since the popup - * needs to be opened before we can focus - */ - Timer focusTimer = new Timer() { - @Override - public void run() { - setFocus(true); - } - }; - - focusTimer.schedule(100); - } - }); - } else { - VConsole.error("Cannot reopen popup, it is already open!"); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event - * .dom.client.ClickEvent) - */ - public void onClick(ClickEvent event) { - if (event.getSource() == calendarToggle && isEnabled()) { - openCalendarPanel(); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google.gwt - * .event.logical.shared.CloseEvent) - */ - public void onClose(CloseEvent event) { - if (event.getSource() == popup) { - buildDate(); - if (!BrowserInfo.get().isTouchDevice()) { - /* - * Move focus to textbox, unless on touch device (avoids opening - * virtual keyboard). - */ - focus(); - } - - // TODO resolve what the "Sigh." is all about and document it here - // Sigh. - Timer t = new Timer() { - @Override - public void run() { - open = false; - } - }; - t.schedule(100); - } - } - - /** - * Sets focus to Calendar panel. - * - * @param focus - */ - public void setFocus(boolean focus) { - calendar.setFocus(focus); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#getFieldExtraWidth() - */ - @Override - protected int getFieldExtraWidth() { - if (fieldExtraWidth < 0) { - fieldExtraWidth = super.getFieldExtraWidth(); - fieldExtraWidth += calendarToggle.getOffsetWidth(); - } - return fieldExtraWidth; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#buildDate() - */ - @Override - protected void buildDate() { - // Save previous value - String previousValue = getText(); - super.buildDate(); - - // Restore previous value if the input could not be parsed - if (!parsable) { - setText(previousValue); - } - } - - /** - * Update the text field contents from the date. See {@link #buildDate()}. - * - * @param forceValid - * true to force the text field to be updated, false to only - * update if the parsable flag is true. - */ - protected void buildDate(boolean forceValid) { - if (forceValid) { - parsable = true; - } - buildDate(); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.gwt.client.ui.VDateField#onBrowserEvent(com.google - * .gwt.user.client.Event) - */ - @Override - public void onBrowserEvent(com.google.gwt.user.client.Event event) { - super.onBrowserEvent(event); - if (DOM.eventGetType(event) == Event.ONKEYDOWN - && event.getKeyCode() == getOpenCalenderPanelKey()) { - openCalendarPanel(); - event.preventDefault(); - } - } - - /** - * Get the key code that opens the calendar panel. By default it is the down - * key but you can override this to be whatever you like - * - * @return - */ - protected int getOpenCalenderPanelKey() { - return KeyCodes.KEY_DOWN; - } - - /** - * Closes the open popup panel - */ - public void closeCalendarPanel() { - if (open) { - popup.hide(true); - } - } - - private final String CALENDAR_TOGGLE_ID = "popupButton"; - - @Override - public Element getSubPartElement(String subPart) { - if (subPart.equals(CALENDAR_TOGGLE_ID)) { - return calendarToggle.getElement(); - } - - return super.getSubPartElement(subPart); - } - - @Override - public String getSubPartName(Element subElement) { - if (calendarToggle.getElement().isOrHasChild(subElement)) { - return CALENDAR_TOGGLE_ID; - } - - return super.getSubPartName(subElement); - } - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import java.util.Date; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.DomEvent; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.event.logical.shared.CloseEvent; +import com.google.gwt.event.logical.shared.CloseHandler; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.PopupPanel; +import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.DateTimeService; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener; +import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener; +import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener; +import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener; + +/** + * Represents a date selection component with a text field and a popup date + * selector. + * + * Note: To change the keyboard assignments used in the popup dialog you + * should extend com.vaadin.terminal.gwt.client.ui.VCalendarPanel + * and then pass set it by calling the + * setCalendarPanel(VCalendarPanel panel) method. + * + */ +public class VPopupCalendar extends VTextualDate implements Paintable, Field, + ClickHandler, CloseHandler, SubPartAware { + + private static final String POPUP_PRIMARY_STYLE_NAME = VDateField.CLASSNAME + + "-popup"; + + private final Button calendarToggle; + + private VCalendarPanel calendar; + + private final VOverlay popup; + private boolean open = false; + private boolean parsable = true; + + public VPopupCalendar() { + super(); + + calendarToggle = new Button(); + calendarToggle.setStyleName(CLASSNAME + "-button"); + calendarToggle.setText(""); + calendarToggle.addClickHandler(this); + // -2 instead of -1 to avoid FocusWidget.onAttach to reset it + calendarToggle.getElement().setTabIndex(-2); + add(calendarToggle); + + calendar = GWT.create(VCalendarPanel.class); + calendar.setFocusOutListener(new FocusOutListener() { + public boolean onFocusOut(DomEvent event) { + event.preventDefault(); + closeCalendarPanel(); + return true; + } + }); + + calendar.setSubmitListener(new SubmitListener() { + public void onSubmit() { + // Update internal value and send valuechange event if immediate + updateValue(calendar.getDate()); + + // Update text field (a must when not immediate). + buildDate(true); + + closeCalendarPanel(); + } + + public void onCancel() { + closeCalendarPanel(); + } + }); + + popup = new VOverlay(true, true, true); + popup.setStyleName(POPUP_PRIMARY_STYLE_NAME); + popup.setWidget(calendar); + popup.addCloseHandler(this); + + DOM.setElementProperty(calendar.getElement(), "id", + "PID_VAADIN_POPUPCAL"); + + sinkEvents(Event.ONKEYDOWN); + + } + + @SuppressWarnings("deprecation") + private void updateValue(Date newDate) { + Date currentDate = getCurrentDate(); + if (currentDate == null || newDate.getTime() != currentDate.getTime()) { + setCurrentDate((Date) newDate.clone()); + getClient().updateVariable(getId(), "year", + newDate.getYear() + 1900, false); + if (getCurrentResolution() > VDateField.RESOLUTION_YEAR) { + getClient().updateVariable(getId(), "month", + newDate.getMonth() + 1, false); + if (getCurrentResolution() > RESOLUTION_MONTH) { + getClient().updateVariable(getId(), "day", + newDate.getDate(), false); + if (getCurrentResolution() > RESOLUTION_DAY) { + getClient().updateVariable(getId(), "hour", + newDate.getHours(), false); + if (getCurrentResolution() > RESOLUTION_HOUR) { + getClient().updateVariable(getId(), "min", + newDate.getMinutes(), false); + if (getCurrentResolution() > RESOLUTION_MIN) { + getClient().updateVariable(getId(), "sec", + newDate.getSeconds(), false); + if (getCurrentResolution() == RESOLUTION_MSEC) { + getClient().updateVariable( + getId(), + "msec", + DateTimeService + .getMilliseconds(newDate), + false); + } + } + } + } + } + } + if (isImmediate()) { + getClient().sendPendingVariableChanges(); + } + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.gwt.client.ui.VTextualDate#updateFromUIDL(com.vaadin + * .terminal.gwt.client.UIDL, + * com.vaadin.terminal.gwt.client.ApplicationConnection) + */ + @Override + @SuppressWarnings("deprecation") + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + boolean lastReadOnlyState = readonly; + boolean lastEnabledState = isEnabled(); + + parsable = uidl.getBooleanAttribute("parsable"); + + super.updateFromUIDL(uidl, client); + + String popupStyleNames = ApplicationConnection.getStyleName( + POPUP_PRIMARY_STYLE_NAME, uidl, false); + popupStyleNames += " " + VDateField.CLASSNAME + "-" + + resolutionToString(currentResolution); + popup.setStyleName(popupStyleNames); + + calendar.setDateTimeService(getDateTimeService()); + calendar.setShowISOWeekNumbers(isShowISOWeekNumbers()); + if (calendar.getResolution() != currentResolution) { + calendar.setResolution(currentResolution); + if (calendar.getDate() != null) { + calendar.setDate((Date) getCurrentDate().clone()); + // force re-render when changing resolution only + calendar.renderCalendar(); + } + } + calendarToggle.setEnabled(enabled); + + if (currentResolution <= RESOLUTION_MONTH) { + calendar.setFocusChangeListener(new FocusChangeListener() { + public void focusChanged(Date date) { + updateValue(date); + buildDate(); + Date date2 = calendar.getDate(); + date2.setYear(date.getYear()); + date2.setMonth(date.getMonth()); + } + }); + } else { + calendar.setFocusChangeListener(null); + } + + if (currentResolution > RESOLUTION_DAY) { + calendar.setTimeChangeListener(new TimeChangeListener() { + public void changed(int hour, int min, int sec, int msec) { + Date d = getDate(); + if (d == null) { + // date currently null, use the value from calendarPanel + // (~ client time at the init of the widget) + d = (Date) calendar.getDate().clone(); + } + d.setHours(hour); + d.setMinutes(min); + d.setSeconds(sec); + DateTimeService.setMilliseconds(d, msec); + + // Always update time changes to the server + updateValue(d); + + // Update text field + buildDate(); + } + }); + } + + if (readonly) { + calendarToggle.addStyleName(CLASSNAME + "-button-readonly"); + } else { + calendarToggle.removeStyleName(CLASSNAME + "-button-readonly"); + } + + if (lastReadOnlyState != readonly || lastEnabledState != isEnabled()) { + // Enabled or readonly state changed. Differences in theming might + // affect the width (for instance if the popup button is hidden) so + // we have to recalculate the width (IF the width of the field is + // fixed) + updateWidth(); + } + + calendarToggle.setEnabled(true); + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.user.client.ui.UIObject#setStyleName(java.lang.String) + */ + @Override + public void setStyleName(String style) { + // make sure the style is there before size calculation + super.setStyleName(style + " " + CLASSNAME + "-popupcalendar"); + } + + /** + * Opens the calendar panel popup + */ + public void openCalendarPanel() { + + if (!open && !readonly) { + open = true; + + if (getCurrentDate() != null) { + calendar.setDate((Date) getCurrentDate().clone()); + } else { + calendar.setDate(new Date()); + } + + // clear previous values + popup.setWidth(""); + popup.setHeight(""); + popup.setPopupPositionAndShow(new PositionCallback() { + 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(); + + // 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 > 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 + popup.setWidth(w + "px"); + popup.setHeight(h + "px"); + + popup.setPopupPosition(l, + t + calendarToggle.getOffsetHeight() + 2); + + /* + * We have to wait a while before focusing since the popup + * needs to be opened before we can focus + */ + Timer focusTimer = new Timer() { + @Override + public void run() { + setFocus(true); + } + }; + + focusTimer.schedule(100); + } + }); + } else { + VConsole.error("Cannot reopen popup, it is already open!"); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event + * .dom.client.ClickEvent) + */ + public void onClick(ClickEvent event) { + if (event.getSource() == calendarToggle && isEnabled()) { + openCalendarPanel(); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google.gwt + * .event.logical.shared.CloseEvent) + */ + public void onClose(CloseEvent event) { + if (event.getSource() == popup) { + buildDate(); + if (!BrowserInfo.get().isTouchDevice()) { + /* + * Move focus to textbox, unless on touch device (avoids opening + * virtual keyboard). + */ + focus(); + } + + // TODO resolve what the "Sigh." is all about and document it here + // Sigh. + Timer t = new Timer() { + @Override + public void run() { + open = false; + } + }; + t.schedule(100); + } + } + + /** + * Sets focus to Calendar panel. + * + * @param focus + */ + public void setFocus(boolean focus) { + calendar.setFocus(focus); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#getFieldExtraWidth() + */ + @Override + protected int getFieldExtraWidth() { + if (fieldExtraWidth < 0) { + fieldExtraWidth = super.getFieldExtraWidth(); + fieldExtraWidth += calendarToggle.getOffsetWidth(); + } + return fieldExtraWidth; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#buildDate() + */ + @Override + protected void buildDate() { + // Save previous value + String previousValue = getText(); + super.buildDate(); + + // Restore previous value if the input could not be parsed + if (!parsable) { + setText(previousValue); + } + } + + /** + * Update the text field contents from the date. See {@link #buildDate()}. + * + * @param forceValid + * true to force the text field to be updated, false to only + * update if the parsable flag is true. + */ + protected void buildDate(boolean forceValid) { + if (forceValid) { + parsable = true; + } + buildDate(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.gwt.client.ui.VDateField#onBrowserEvent(com.google + * .gwt.user.client.Event) + */ + @Override + public void onBrowserEvent(com.google.gwt.user.client.Event event) { + super.onBrowserEvent(event); + if (DOM.eventGetType(event) == Event.ONKEYDOWN + && event.getKeyCode() == getOpenCalenderPanelKey()) { + openCalendarPanel(); + event.preventDefault(); + } + } + + /** + * Get the key code that opens the calendar panel. By default it is the down + * key but you can override this to be whatever you like + * + * @return + */ + protected int getOpenCalenderPanelKey() { + return KeyCodes.KEY_DOWN; + } + + /** + * Closes the open popup panel + */ + public void closeCalendarPanel() { + if (open) { + popup.hide(true); + } + } + + private final String CALENDAR_TOGGLE_ID = "popupButton"; + + @Override + public Element getSubPartElement(String subPart) { + if (subPart.equals(CALENDAR_TOGGLE_ID)) { + return calendarToggle.getElement(); + } + + return super.getSubPartElement(subPart); + } + + @Override + public String getSubPartName(Element subElement) { + if (calendarToggle.getElement().isOrHasChild(subElement)) { + return CALENDAR_TOGGLE_ID; + } + + return super.getSubPartName(subElement); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSlider.java b/src/com/vaadin/terminal/gwt/client/ui/VSlider.java index 9dfab44b93..a001ca7f13 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VSlider.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VSlider.java @@ -1,599 +1,603 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -// -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.core.client.Scheduler.ScheduledCommand; -import com.google.gwt.event.dom.client.KeyCodes; -import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.ui.HTML; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -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; -import com.vaadin.terminal.gwt.client.VConsole; - -public class VSlider extends SimpleFocusablePanel implements Paintable, Field, - ContainerResizedListener { - - public static final String CLASSNAME = "v-slider"; - - /** - * Minimum size (width or height, depending on orientation) of the slider - * base. - */ - private static final int MIN_SIZE = 50; - - ApplicationConnection client; - - String id; - - private boolean immediate; - private boolean disabled; - private boolean readonly; - private boolean scrollbarStyle; - - private int acceleration = 1; - private int handleSize; - private double min; - private double max; - private int resolution; - private Double value; - private boolean vertical; - private boolean arrows; - - private final HTML feedback = new HTML("", false); - private final VOverlay feedbackPopup = new VOverlay(true, false, true) { - @Override - public void show() { - super.show(); - updateFeedbackPosition(); - } - }; - - /* DOM element for slider's base */ - private final Element base; - private final int BASE_BORDER_WIDTH = 1; - - /* DOM element for slider's handle */ - private final Element handle; - - /* DOM element for decrement arrow */ - private final Element smaller; - - /* DOM element for increment arrow */ - private final Element bigger; - - /* Temporary dragging/animation variables */ - private boolean dragging = false; - - private VLazyExecutor delayedValueUpdater = new VLazyExecutor(100, - new ScheduledCommand() { - - public void execute() { - updateValueToServer(); - acceleration = 1; - } - }); - - public VSlider() { - super(); - - base = DOM.createDiv(); - handle = DOM.createDiv(); - smaller = DOM.createDiv(); - bigger = DOM.createDiv(); - - setStyleName(CLASSNAME); - DOM.setElementProperty(base, "className", CLASSNAME + "-base"); - DOM.setElementProperty(handle, "className", CLASSNAME + "-handle"); - DOM.setElementProperty(smaller, "className", CLASSNAME + "-smaller"); - DOM.setElementProperty(bigger, "className", CLASSNAME + "-bigger"); - - DOM.appendChild(getElement(), bigger); - DOM.appendChild(getElement(), smaller); - DOM.appendChild(getElement(), base); - DOM.appendChild(base, handle); - - // Hide initially - DOM.setStyleAttribute(smaller, "display", "none"); - DOM.setStyleAttribute(bigger, "display", "none"); - DOM.setStyleAttribute(handle, "visibility", "hidden"); - - sinkEvents(Event.MOUSEEVENTS | Event.ONMOUSEWHEEL | Event.KEYEVENTS - | Event.FOCUSEVENTS | Event.TOUCHEVENTS); - - feedbackPopup.addStyleName(CLASSNAME + "-feedback"); - feedbackPopup.setWidget(feedback); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - - this.client = client; - id = uidl.getId(); - - // Ensure correct implementation - if (client.updateComponent(this, uidl, true)) { - return; - } - - immediate = uidl.getBooleanAttribute("immediate"); - disabled = uidl.getBooleanAttribute("disabled"); - readonly = uidl.getBooleanAttribute("readonly"); - - vertical = uidl.hasAttribute("vertical"); - arrows = uidl.hasAttribute("arrows"); - - String style = ""; - if (uidl.hasAttribute("style")) { - style = uidl.getStringAttribute("style"); - } - - scrollbarStyle = style.indexOf("scrollbar") > -1; - - if (arrows) { - DOM.setStyleAttribute(smaller, "display", "block"); - DOM.setStyleAttribute(bigger, "display", "block"); - } - - if (vertical) { - addStyleName(CLASSNAME + "-vertical"); - } else { - removeStyleName(CLASSNAME + "-vertical"); - } - - min = uidl.getDoubleAttribute("min"); - max = uidl.getDoubleAttribute("max"); - resolution = uidl.getIntAttribute("resolution"); - value = new Double(uidl.getDoubleVariable("value")); - - setFeedbackValue(value); - - handleSize = uidl.getIntAttribute("hsize"); - - buildBase(); - - if (!vertical) { - // Draw handle with a delay to allow base to gain maximum width - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - buildHandle(); - setValue(value, false); - } - }); - } else { - buildHandle(); - setValue(value, false); - } - } - - private void setFeedbackValue(double value) { - String currentValue = "" + value; - if (resolution == 0) { - currentValue = "" + new Double(value).intValue(); - } - feedback.setText(currentValue); - } - - private void updateFeedbackPosition() { - if (vertical) { - feedbackPopup.setPopupPosition( - DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth(), - DOM.getAbsoluteTop(handle) + handle.getOffsetHeight() / 2 - - feedbackPopup.getOffsetHeight() / 2); - } else { - feedbackPopup.setPopupPosition( - DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth() / 2 - - feedbackPopup.getOffsetWidth() / 2, - DOM.getAbsoluteTop(handle) - - feedbackPopup.getOffsetHeight()); - } - } - - private void buildBase() { - final String styleAttribute = vertical ? "height" : "width"; - final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; - - final Element p = DOM.getParent(getElement()); - if (DOM.getElementPropertyInt(p, domProperty) > 50) { - if (vertical) { - setHeight(); - } else { - DOM.setStyleAttribute(base, styleAttribute, ""); - } - } else { - // Set minimum size and adjust after all components have - // (supposedly) been drawn completely. - DOM.setStyleAttribute(base, styleAttribute, MIN_SIZE + "px"); - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - final Element p = DOM.getParent(getElement()); - if (DOM.getElementPropertyInt(p, domProperty) > (MIN_SIZE + 5)) { - if (vertical) { - setHeight(); - } else { - DOM.setStyleAttribute(base, styleAttribute, ""); - } - // Ensure correct position - setValue(value, false); - } - } - }); - } - - // TODO attach listeners for focusing and arrow keys - } - - private void buildHandle() { - final String styleAttribute = vertical ? "height" : "width"; - final String handleAttribute = vertical ? "marginTop" : "marginLeft"; - final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; - - DOM.setStyleAttribute(handle, handleAttribute, "0"); - - if (scrollbarStyle) { - // Only stretch the handle if scrollbar style is set. - int s = (int) (Double.parseDouble(DOM.getElementProperty(base, - domProperty)) / 100 * handleSize); - if (handleSize == -1) { - final int baseS = Integer.parseInt(DOM.getElementProperty(base, - domProperty)); - final double range = (max - min) * (resolution + 1) * 3; - s = (int) (baseS - range); - } - if (s < 3) { - s = 3; - } - DOM.setStyleAttribute(handle, styleAttribute, s + "px"); - } else { - DOM.setStyleAttribute(handle, styleAttribute, ""); - } - - // Restore visibility - DOM.setStyleAttribute(handle, "visibility", "visible"); - - } - - private void setValue(Double value, boolean updateToServer) { - if (value == null) { - return; - } - - if (value < min) { - value = min; - } else if (value > max) { - value = max; - } - - // Update handle position - final String styleAttribute = vertical ? "marginTop" : "marginLeft"; - final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; - final int handleSize = Integer.parseInt(DOM.getElementProperty(handle, - domProperty)); - final int baseSize = Integer.parseInt(DOM.getElementProperty(base, - domProperty)) - (2 * BASE_BORDER_WIDTH); - - final int range = baseSize - handleSize; - double v = value.doubleValue(); - - // Round value to resolution - if (resolution > 0) { - v = Math.round(v * Math.pow(10, resolution)); - v = v / Math.pow(10, resolution); - } else { - v = Math.round(v); - } - final double valueRange = max - min; - double p = 0; - if (valueRange > 0) { - p = range * ((v - min) / valueRange); - } - if (p < 0) { - p = 0; - } - if (vertical) { - // IE6 rounding behaves a little unstable, reduce one pixel so the - // containing element (base) won't expand without limits - p = range - p - (BrowserInfo.get().isIE6() ? 1 : 0); - } - final double pos = p; - - DOM.setStyleAttribute(handle, styleAttribute, (Math.round(pos)) + "px"); - - // Update value - this.value = new Double(v); - setFeedbackValue(v); - - if (updateToServer) { - updateValueToServer(); - } - } - - @Override - public void onBrowserEvent(Event event) { - if (disabled || readonly) { - return; - } - final Element targ = DOM.eventGetTarget(event); - - if (DOM.eventGetType(event) == Event.ONMOUSEWHEEL) { - processMouseWheelEvent(event); - } else if (dragging || targ == handle) { - processHandleEvent(event); - } else if (targ == smaller) { - decreaseValue(true); - } else if (targ == bigger) { - increaseValue(true); - } else if (DOM.eventGetType(event) == Event.MOUSEEVENTS) { - processBaseEvent(event); - } else if ((BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYPRESS) - || (!BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYDOWN)) { - - if (handleNavigation(event.getKeyCode(), event.getCtrlKey(), - event.getShiftKey())) { - - feedbackPopup.show(); - - delayedValueUpdater.trigger(); - - DOM.eventPreventDefault(event); - DOM.eventCancelBubble(event, true); - } - } else if (targ.equals(getElement()) - && DOM.eventGetType(event) == Event.ONFOCUS) { - feedbackPopup.show(); - } else if (targ.equals(getElement()) - && DOM.eventGetType(event) == Event.ONBLUR) { - feedbackPopup.hide(); - } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { - feedbackPopup.show(); - } - if(Util.isTouchEvent(event)) { - event.preventDefault(); // avoid simulated events - event.stopPropagation(); - } - } - - private void processMouseWheelEvent(final Event event) { - final int dir = DOM.eventGetMouseWheelVelocityY(event); - - if (dir < 0) { - increaseValue(false); - } else { - decreaseValue(false); - } - - delayedValueUpdater.trigger(); - - DOM.eventPreventDefault(event); - DOM.eventCancelBubble(event, true); - } - - private void processHandleEvent(Event event) { - switch (DOM.eventGetType(event)) { - case Event.ONMOUSEDOWN: - case Event.ONTOUCHSTART: - if (!disabled && !readonly) { - focus(); - feedbackPopup.show(); - dragging = true; - DOM.setElementProperty(handle, "className", CLASSNAME - + "-handle " + CLASSNAME + "-handle-active"); - DOM.setCapture(getElement()); - DOM.eventPreventDefault(event); // prevent selecting text - DOM.eventCancelBubble(event, true); - event.stopPropagation(); - VConsole.log("Slider move start"); - } - break; - case Event.ONMOUSEMOVE: - case Event.ONTOUCHMOVE: - if (dragging) { - VConsole.log("Slider move"); - setValueByEvent(event, false); - updateFeedbackPosition(); - event.stopPropagation(); - } - break; - case Event.ONTOUCHEND: - feedbackPopup.hide(); - case Event.ONMOUSEUP: - // feedbackPopup.hide(); - VConsole.log("Slider move end"); - dragging = false; - DOM.setElementProperty(handle, "className", CLASSNAME + "-handle"); - DOM.releaseCapture(getElement()); - setValueByEvent(event, true); - event.stopPropagation(); - break; - default: - break; - } - } - - private void processBaseEvent(Event event) { - if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { - if (!disabled && !readonly && !dragging) { - setValueByEvent(event, true); - DOM.eventCancelBubble(event, true); - } - } - } - - private void decreaseValue(boolean updateToServer) { - setValue(new Double(value.doubleValue() - Math.pow(10, -resolution)), - updateToServer); - } - - private void increaseValue(boolean updateToServer) { - setValue(new Double(value.doubleValue() + Math.pow(10, -resolution)), - updateToServer); - } - - private void setValueByEvent(Event event, boolean updateToServer) { - double v = min; // Fallback to min - - final int coord = getEventPosition(event); - - final int handleSize, baseSize, baseOffset; - if (vertical) { - handleSize = handle.getOffsetHeight(); - baseSize = base.getOffsetHeight(); - baseOffset = base.getAbsoluteTop() - Window.getScrollTop() - - handleSize / 2; - } else { - handleSize = handle.getOffsetWidth(); - baseSize = base.getOffsetWidth(); - baseOffset = base.getAbsoluteLeft() - Window.getScrollLeft() - + handleSize / 2; - } - - if (vertical) { - v = ((baseSize - (coord - baseOffset)) / (double) (baseSize - handleSize)) - * (max - min) + min; - } else { - v = ((coord - baseOffset) / (double) (baseSize - handleSize)) - * (max - min) + min; - } - - if (v < min) { - v = min; - } else if (v > max) { - v = max; - } - - setValue(v, updateToServer); - } - - /** - * TODO consider extracting touches support to an impl class specific for - * webkit (only browser that really supports touches). - * - * @param event - * @return - */ - protected int getEventPosition(Event event) { - if (vertical) { - return Util.getTouchOrMouseClientY(event); - } else { - return Util.getTouchOrMouseClientX(event); - } - } - - public void iLayout() { - if (vertical) { - setHeight(); - } - // Update handle position - setValue(value, false); - } - - private void setHeight() { - // Calculate decoration size - DOM.setStyleAttribute(base, "height", "0"); - DOM.setStyleAttribute(base, "overflow", "hidden"); - int h = DOM.getElementPropertyInt(getElement(), "offsetHeight"); - if (h < MIN_SIZE) { - h = MIN_SIZE; - } - DOM.setStyleAttribute(base, "height", h + "px"); - DOM.setStyleAttribute(base, "overflow", ""); - } - - private void updateValueToServer() { - client.updateVariable(id, "value", value.doubleValue(), immediate); - } - - /** - * Handles the keyboard events handled by the Slider - * - * @param event - * The keyboard event received - * @return true iff the navigation event was handled - */ - public boolean handleNavigation(int keycode, boolean ctrl, boolean shift) { - - // No support for ctrl moving - if (ctrl) { - return false; - } - - if ((keycode == getNavigationUpKey() && vertical) - || (keycode == getNavigationRightKey() && !vertical)) { - if (shift) { - for (int a = 0; a < acceleration; a++) { - increaseValue(false); - } - acceleration++; - } else { - increaseValue(false); - } - return true; - } else if (keycode == getNavigationDownKey() && vertical - || (keycode == getNavigationLeftKey() && !vertical)) { - if (shift) { - for (int a = 0; a < acceleration; a++) { - decreaseValue(false); - } - acceleration++; - } else { - decreaseValue(false); - } - return true; - } - - return false; - } - - /** - * Get the key that increases the vertical slider. By default it is the up - * arrow key but by overriding this you can change the key to whatever you - * want. - * - * @return The keycode of the key - */ - protected int getNavigationUpKey() { - return KeyCodes.KEY_UP; - } - - /** - * Get the key that decreases the vertical slider. By default it is the down - * arrow key but by overriding this you can change the key to whatever you - * want. - * - * @return The keycode of the key - */ - protected int getNavigationDownKey() { - return KeyCodes.KEY_DOWN; - } - - /** - * Get the key that decreases the horizontal slider. By default it is the - * left arrow key but by overriding this you can change the key to whatever - * you want. - * - * @return The keycode of the key - */ - protected int getNavigationLeftKey() { - return KeyCodes.KEY_LEFT; - } - - /** - * Get the key that increases the horizontal slider. By default it is the - * right arrow key but by overriding this you can change the key to whatever - * you want. - * - * @return The keycode of the key - */ - protected int getNavigationRightKey() { - return KeyCodes.KEY_RIGHT; - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ +// +package com.vaadin.terminal.gwt.client.ui; + +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.HTML; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +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; +import com.vaadin.terminal.gwt.client.VConsole; + +public class VSlider extends SimpleFocusablePanel implements Paintable, Field, + ContainerResizedListener { + + public static final String CLASSNAME = "v-slider"; + + /** + * Minimum size (width or height, depending on orientation) of the slider + * base. + */ + private static final int MIN_SIZE = 50; + + ApplicationConnection client; + + String id; + + private boolean immediate; + private boolean disabled; + private boolean readonly; + private boolean scrollbarStyle; + + private int acceleration = 1; + private int handleSize; + private double min; + private double max; + private int resolution; + private Double value; + private boolean vertical; + private boolean arrows; + + private final HTML feedback = new HTML("", false); + private final VOverlay feedbackPopup = new VOverlay(true, false, true) { + @Override + public void show() { + super.show(); + updateFeedbackPosition(); + } + }; + + /* DOM element for slider's base */ + private final Element base; + private final int BASE_BORDER_WIDTH = 1; + + /* DOM element for slider's handle */ + private final Element handle; + + /* DOM element for decrement arrow */ + private final Element smaller; + + /* DOM element for increment arrow */ + private final Element bigger; + + /* Temporary dragging/animation variables */ + private boolean dragging = false; + + private VLazyExecutor delayedValueUpdater = new VLazyExecutor(100, + new ScheduledCommand() { + + public void execute() { + updateValueToServer(); + acceleration = 1; + } + }); + + public VSlider() { + super(); + + base = DOM.createDiv(); + handle = DOM.createDiv(); + smaller = DOM.createDiv(); + bigger = DOM.createDiv(); + + setStyleName(CLASSNAME); + DOM.setElementProperty(base, "className", CLASSNAME + "-base"); + DOM.setElementProperty(handle, "className", CLASSNAME + "-handle"); + DOM.setElementProperty(smaller, "className", CLASSNAME + "-smaller"); + DOM.setElementProperty(bigger, "className", CLASSNAME + "-bigger"); + + DOM.appendChild(getElement(), bigger); + DOM.appendChild(getElement(), smaller); + DOM.appendChild(getElement(), base); + DOM.appendChild(base, handle); + + // Hide initially + DOM.setStyleAttribute(smaller, "display", "none"); + DOM.setStyleAttribute(bigger, "display", "none"); + DOM.setStyleAttribute(handle, "visibility", "hidden"); + + sinkEvents(Event.MOUSEEVENTS | Event.ONMOUSEWHEEL | Event.KEYEVENTS + | Event.FOCUSEVENTS | Event.TOUCHEVENTS); + + feedbackPopup.addStyleName(CLASSNAME + "-feedback"); + feedbackPopup.setWidget(feedback); + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + + this.client = client; + id = uidl.getId(); + + // Ensure correct implementation + if (client.updateComponent(this, uidl, true)) { + return; + } + + immediate = uidl.getBooleanAttribute("immediate"); + disabled = uidl.getBooleanAttribute("disabled"); + readonly = uidl.getBooleanAttribute("readonly"); + + vertical = uidl.hasAttribute("vertical"); + arrows = uidl.hasAttribute("arrows"); + + String style = ""; + if (uidl.hasAttribute("style")) { + style = uidl.getStringAttribute("style"); + } + + scrollbarStyle = style.indexOf("scrollbar") > -1; + + if (arrows) { + DOM.setStyleAttribute(smaller, "display", "block"); + DOM.setStyleAttribute(bigger, "display", "block"); + } + + if (vertical) { + addStyleName(CLASSNAME + "-vertical"); + } else { + removeStyleName(CLASSNAME + "-vertical"); + } + + min = uidl.getDoubleAttribute("min"); + max = uidl.getDoubleAttribute("max"); + resolution = uidl.getIntAttribute("resolution"); + value = new Double(uidl.getDoubleVariable("value")); + + setFeedbackValue(value); + + handleSize = uidl.getIntAttribute("hsize"); + + buildBase(); + + if (!vertical) { + // Draw handle with a delay to allow base to gain maximum width + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + buildHandle(); + setValue(value, false); + } + }); + } else { + buildHandle(); + setValue(value, false); + } + } + + private void setFeedbackValue(double value) { + String currentValue = "" + value; + if (resolution == 0) { + currentValue = "" + new Double(value).intValue(); + } + feedback.setText(currentValue); + } + + private void updateFeedbackPosition() { + if (vertical) { + feedbackPopup.setPopupPosition( + DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth(), + DOM.getAbsoluteTop(handle) + handle.getOffsetHeight() / 2 + - feedbackPopup.getOffsetHeight() / 2); + } else { + feedbackPopup.setPopupPosition( + DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth() / 2 + - feedbackPopup.getOffsetWidth() / 2, + DOM.getAbsoluteTop(handle) + - feedbackPopup.getOffsetHeight()); + } + } + + private void buildBase() { + final String styleAttribute = vertical ? "height" : "width"; + final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; + + final Element p = DOM.getParent(getElement()); + if (DOM.getElementPropertyInt(p, domProperty) > 50) { + if (vertical) { + setHeight(); + } else { + DOM.setStyleAttribute(base, styleAttribute, ""); + } + } else { + // Set minimum size and adjust after all components have + // (supposedly) been drawn completely. + DOM.setStyleAttribute(base, styleAttribute, MIN_SIZE + "px"); + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + final Element p = DOM.getParent(getElement()); + if (DOM.getElementPropertyInt(p, domProperty) > (MIN_SIZE + 5)) { + if (vertical) { + setHeight(); + } else { + DOM.setStyleAttribute(base, styleAttribute, ""); + } + // Ensure correct position + setValue(value, false); + } + } + }); + } + + // TODO attach listeners for focusing and arrow keys + } + + private void buildHandle() { + final String styleAttribute = vertical ? "height" : "width"; + final String handleAttribute = vertical ? "marginTop" : "marginLeft"; + final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; + + DOM.setStyleAttribute(handle, handleAttribute, "0"); + + if (scrollbarStyle) { + // Only stretch the handle if scrollbar style is set. + int s = (int) (Double.parseDouble(DOM.getElementProperty(base, + domProperty)) / 100 * handleSize); + if (handleSize == -1) { + final int baseS = Integer.parseInt(DOM.getElementProperty(base, + domProperty)); + final double range = (max - min) * (resolution + 1) * 3; + s = (int) (baseS - range); + } + if (s < 3) { + s = 3; + } + DOM.setStyleAttribute(handle, styleAttribute, s + "px"); + } else { + DOM.setStyleAttribute(handle, styleAttribute, ""); + } + + // Restore visibility + DOM.setStyleAttribute(handle, "visibility", "visible"); + + } + + private void setValue(Double value, boolean updateToServer) { + if (value == null) { + return; + } + + if (value < min) { + value = min; + } else if (value > max) { + value = max; + } + + // Update handle position + final String styleAttribute = vertical ? "marginTop" : "marginLeft"; + final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; + final int handleSize = Integer.parseInt(DOM.getElementProperty(handle, + domProperty)); + final int baseSize = Integer.parseInt(DOM.getElementProperty(base, + domProperty)) - (2 * BASE_BORDER_WIDTH); + + final int range = baseSize - handleSize; + double v = value.doubleValue(); + + // Round value to resolution + if (resolution > 0) { + v = Math.round(v * Math.pow(10, resolution)); + v = v / Math.pow(10, resolution); + } else { + v = Math.round(v); + } + final double valueRange = max - min; + double p = 0; + if (valueRange > 0) { + p = range * ((v - min) / valueRange); + } + if (p < 0) { + p = 0; + } + if (vertical) { + // IE6 rounding behaves a little unstable, reduce one pixel so the + // containing element (base) won't expand without limits + p = range - p - (BrowserInfo.get().isIE6() ? 1 : 0); + } + final double pos = p; + + DOM.setStyleAttribute(handle, styleAttribute, (Math.round(pos)) + "px"); + + // Update value + this.value = new Double(v); + setFeedbackValue(v); + + if (updateToServer) { + updateValueToServer(); + } + } + + @Override + public void onBrowserEvent(Event event) { + if (disabled || readonly) { + return; + } + final Element targ = DOM.eventGetTarget(event); + + if (DOM.eventGetType(event) == Event.ONMOUSEWHEEL) { + processMouseWheelEvent(event); + } else if (dragging || targ == handle) { + processHandleEvent(event); + } else if (targ == smaller) { + decreaseValue(true); + } else if (targ == bigger) { + increaseValue(true); + } else if (DOM.eventGetType(event) == Event.MOUSEEVENTS) { + processBaseEvent(event); + } else if ((BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYPRESS) + || (!BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYDOWN)) { + + if (handleNavigation(event.getKeyCode(), event.getCtrlKey(), + event.getShiftKey())) { + + feedbackPopup.show(); + + delayedValueUpdater.trigger(); + + DOM.eventPreventDefault(event); + DOM.eventCancelBubble(event, true); + } + } else if (targ.equals(getElement()) + && DOM.eventGetType(event) == Event.ONFOCUS) { + feedbackPopup.show(); + } else if (targ.equals(getElement()) + && DOM.eventGetType(event) == Event.ONBLUR) { + feedbackPopup.hide(); + } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { + feedbackPopup.show(); + } + if(Util.isTouchEvent(event)) { + event.preventDefault(); // avoid simulated events + event.stopPropagation(); + } + } + + private void processMouseWheelEvent(final Event event) { + final int dir = DOM.eventGetMouseWheelVelocityY(event); + + if (dir < 0) { + increaseValue(false); + } else { + decreaseValue(false); + } + + delayedValueUpdater.trigger(); + + DOM.eventPreventDefault(event); + DOM.eventCancelBubble(event, true); + } + + private void processHandleEvent(Event event) { + switch (DOM.eventGetType(event)) { + case Event.ONMOUSEDOWN: + case Event.ONTOUCHSTART: + if (!disabled && !readonly) { + focus(); + feedbackPopup.show(); + dragging = true; + DOM.setElementProperty(handle, "className", CLASSNAME + + "-handle " + CLASSNAME + "-handle-active"); + DOM.setCapture(getElement()); + DOM.eventPreventDefault(event); // prevent selecting text + DOM.eventCancelBubble(event, true); + event.stopPropagation(); + VConsole.log("Slider move start"); + } + break; + case Event.ONMOUSEMOVE: + case Event.ONTOUCHMOVE: + if (dragging) { + VConsole.log("Slider move"); + setValueByEvent(event, false); + updateFeedbackPosition(); + event.stopPropagation(); + } + break; + case Event.ONTOUCHEND: + feedbackPopup.hide(); + case Event.ONMOUSEUP: + // feedbackPopup.hide(); + VConsole.log("Slider move end"); + dragging = false; + DOM.setElementProperty(handle, "className", CLASSNAME + "-handle"); + DOM.releaseCapture(getElement()); + setValueByEvent(event, true); + event.stopPropagation(); + break; + default: + break; + } + } + + private void processBaseEvent(Event event) { + if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { + if (!disabled && !readonly && !dragging) { + setValueByEvent(event, true); + DOM.eventCancelBubble(event, true); + } + } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN && dragging) { + dragging = false; + DOM.releaseCapture(getElement()); + setValueByEvent(event, true); + } + } + + private void decreaseValue(boolean updateToServer) { + setValue(new Double(value.doubleValue() - Math.pow(10, -resolution)), + updateToServer); + } + + private void increaseValue(boolean updateToServer) { + setValue(new Double(value.doubleValue() + Math.pow(10, -resolution)), + updateToServer); + } + + private void setValueByEvent(Event event, boolean updateToServer) { + double v = min; // Fallback to min + + final int coord = getEventPosition(event); + + final int handleSize, baseSize, baseOffset; + if (vertical) { + handleSize = handle.getOffsetHeight(); + baseSize = base.getOffsetHeight(); + baseOffset = base.getAbsoluteTop() - Window.getScrollTop() + - handleSize / 2; + } else { + handleSize = handle.getOffsetWidth(); + baseSize = base.getOffsetWidth(); + baseOffset = base.getAbsoluteLeft() - Window.getScrollLeft() + + handleSize / 2; + } + + if (vertical) { + v = ((baseSize - (coord - baseOffset)) / (double) (baseSize - handleSize)) + * (max - min) + min; + } else { + v = ((coord - baseOffset) / (double) (baseSize - handleSize)) + * (max - min) + min; + } + + if (v < min) { + v = min; + } else if (v > max) { + v = max; + } + + setValue(v, updateToServer); + } + + /** + * TODO consider extracting touches support to an impl class specific for + * webkit (only browser that really supports touches). + * + * @param event + * @return + */ + protected int getEventPosition(Event event) { + if (vertical) { + return Util.getTouchOrMouseClientY(event); + } else { + return Util.getTouchOrMouseClientX(event); + } + } + + public void iLayout() { + if (vertical) { + setHeight(); + } + // Update handle position + setValue(value, false); + } + + private void setHeight() { + // Calculate decoration size + DOM.setStyleAttribute(base, "height", "0"); + DOM.setStyleAttribute(base, "overflow", "hidden"); + int h = DOM.getElementPropertyInt(getElement(), "offsetHeight"); + if (h < MIN_SIZE) { + h = MIN_SIZE; + } + DOM.setStyleAttribute(base, "height", h + "px"); + DOM.setStyleAttribute(base, "overflow", ""); + } + + private void updateValueToServer() { + client.updateVariable(id, "value", value.doubleValue(), immediate); + } + + /** + * Handles the keyboard events handled by the Slider + * + * @param event + * The keyboard event received + * @return true iff the navigation event was handled + */ + public boolean handleNavigation(int keycode, boolean ctrl, boolean shift) { + + // No support for ctrl moving + if (ctrl) { + return false; + } + + if ((keycode == getNavigationUpKey() && vertical) + || (keycode == getNavigationRightKey() && !vertical)) { + if (shift) { + for (int a = 0; a < acceleration; a++) { + increaseValue(false); + } + acceleration++; + } else { + increaseValue(false); + } + return true; + } else if (keycode == getNavigationDownKey() && vertical + || (keycode == getNavigationLeftKey() && !vertical)) { + if (shift) { + for (int a = 0; a < acceleration; a++) { + decreaseValue(false); + } + acceleration++; + } else { + decreaseValue(false); + } + return true; + } + + return false; + } + + /** + * Get the key that increases the vertical slider. By default it is the up + * arrow key but by overriding this you can change the key to whatever you + * want. + * + * @return The keycode of the key + */ + protected int getNavigationUpKey() { + return KeyCodes.KEY_UP; + } + + /** + * Get the key that decreases the vertical slider. By default it is the down + * arrow key but by overriding this you can change the key to whatever you + * want. + * + * @return The keycode of the key + */ + protected int getNavigationDownKey() { + return KeyCodes.KEY_DOWN; + } + + /** + * Get the key that decreases the horizontal slider. By default it is the + * left arrow key but by overriding this you can change the key to whatever + * you want. + * + * @return The keycode of the key + */ + protected int getNavigationLeftKey() { + return KeyCodes.KEY_LEFT; + } + + /** + * Get the key that increases the horizontal slider. By default it is the + * right arrow key but by overriding this you can change the key to whatever + * you want. + * + * @return The keycode of the key + */ + protected int getNavigationRightKey() { + return KeyCodes.KEY_RIGHT; + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheetPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheetPanel.java index c33daed440..126b0ebea1 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheetPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheetPanel.java @@ -1,214 +1,214 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.dom.client.Node; -import com.google.gwt.dom.client.NodeList; -import com.google.gwt.event.dom.client.TouchStartEvent; -import com.google.gwt.event.dom.client.TouchStartHandler; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.ui.ComplexPanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.Util; - -/** - * A panel that displays all of its child widgets in a 'deck', where only one - * can be visible at a time. It is used by - * {@link com.vaadin.terminal.gwt.client.ui.VTabsheet}. - * - * This class has the same basic functionality as the GWT DeckPanel - * {@link com.google.gwt.user.client.ui.DeckPanel}, with the exception that it - * doesn't manipulate the child widgets' width and height attributes. - */ -public class VTabsheetPanel extends ComplexPanel { - - private Widget visibleWidget; - private TouchScrollDelegate touchScrollDelegate; - - /** - * Creates an empty tabsheet panel. - */ - public VTabsheetPanel() { - setElement(DOM.createDiv()); - sinkEvents(Event.TOUCHEVENTS); - addDomHandler(new TouchStartHandler() { - public void onTouchStart(TouchStartEvent event) { - /* - * All container elements needs to be scrollable by one finger. - * Update the scrollable element list of touch delegate on each - * touch start. - */ - NodeList childNodes = getElement().getChildNodes(); - Element[] elements = new Element[childNodes.getLength()]; - for (int i = 0; i < elements.length; i++) { - elements[i] = (Element) childNodes.getItem(i); - } - getTouchScrollDelegate().setElements(elements); - getTouchScrollDelegate().onTouchStart(event); - } - }, TouchStartEvent.getType()); - } - - protected TouchScrollDelegate getTouchScrollDelegate() { - if (touchScrollDelegate == null) { - touchScrollDelegate = new TouchScrollDelegate(); - } - return touchScrollDelegate; - - } - - /** - * Adds the specified widget to the deck. - * - * @param w - * the widget to be added - */ - @Override - public void add(Widget w) { - Element el = createContainerElement(); - DOM.appendChild(getElement(), el); - super.add(w, el); - } - - private Element createContainerElement() { - Element el = DOM.createDiv(); - DOM.setStyleAttribute(el, "position", "absolute"); - DOM.setStyleAttribute(el, "overflow", "auto"); - hide(el); - return el; - } - - /** - * Gets the index of the currently-visible widget. - * - * @return the visible widget's index - */ - public int getVisibleWidget() { - return getWidgetIndex(visibleWidget); - } - - /** - * Inserts a widget before the specified index. - * - * @param w - * the widget to be inserted - * @param beforeIndex - * the index before which it will be inserted - * @throws IndexOutOfBoundsException - * if beforeIndex is out of range - */ - public void insert(Widget w, int beforeIndex) { - Element el = createContainerElement(); - DOM.insertChild(getElement(), el, beforeIndex); - super.insert(w, el, beforeIndex, false); - } - - @Override - public boolean remove(Widget w) { - Element child = w.getElement(); - Element parent = null; - if (child != null) { - parent = DOM.getParent(child); - } - final boolean removed = super.remove(w); - if (removed) { - if (visibleWidget == w) { - visibleWidget = null; - } - if (parent != null) { - DOM.removeChild(getElement(), parent); - } - } - return removed; - } - - /** - * Shows the widget at the specified index. This causes the currently- - * visible widget to be hidden. - * - * @param index - * the index of the widget to be shown - */ - public void showWidget(int index) { - checkIndexBoundsForAccess(index); - Widget newVisible = getWidget(index); - if (visibleWidget != newVisible) { - if (visibleWidget != null) { - hide(DOM.getParent(visibleWidget.getElement())); - } - visibleWidget = newVisible; - unHide(DOM.getParent(visibleWidget.getElement())); - } - } - - private void hide(Element e) { - DOM.setStyleAttribute(e, "visibility", "hidden"); - DOM.setStyleAttribute(e, "top", "-100000px"); - DOM.setStyleAttribute(e, "left", "-100000px"); - } - - private void unHide(Element e) { - DOM.setStyleAttribute(e, "top", "0px"); - DOM.setStyleAttribute(e, "left", "0px"); - DOM.setStyleAttribute(e, "visibility", ""); - } - - public void fixVisibleTabSize(int width, int height, int minWidth) { - if (visibleWidget == null) { - return; - } - - boolean dynamicHeight = false; - - if (height < 0) { - height = visibleWidget.getOffsetHeight(); - dynamicHeight = true; - } - if (width < 0) { - width = visibleWidget.getOffsetWidth(); - } - if (width < minWidth) { - width = minWidth; - } - - Element wrapperDiv = (Element) visibleWidget.getElement() - .getParentElement(); - - // width first - getElement().getStyle().setPropertyPx("width", width); - wrapperDiv.getStyle().setPropertyPx("width", width); - - if (dynamicHeight) { - // height of widget might have changed due wrapping - height = visibleWidget.getOffsetHeight(); - } - // v-tabsheet-tabsheetpanel height - getElement().getStyle().setPropertyPx("height", height); - - // widget wrapper height - wrapperDiv.getStyle().setPropertyPx("height", height); - runWebkitOverflowAutoFix(); - } - - public void runWebkitOverflowAutoFix() { - if (visibleWidget != null) { - Util.runWebkitOverflowAutoFix(DOM.getParent(visibleWidget - .getElement())); - } - - } - - public void replaceComponent(Widget oldComponent, Widget newComponent) { - boolean isVisible = (visibleWidget == oldComponent); - int widgetIndex = getWidgetIndex(oldComponent); - remove(oldComponent); - insert(newComponent, widgetIndex); - if (isVisible) { - showWidget(widgetIndex); - } - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.NodeList; +import com.google.gwt.event.dom.client.TouchStartEvent; +import com.google.gwt.event.dom.client.TouchStartHandler; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.ComplexPanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.Util; + +/** + * A panel that displays all of its child widgets in a 'deck', where only one + * can be visible at a time. It is used by + * {@link com.vaadin.terminal.gwt.client.ui.VTabsheet}. + * + * This class has the same basic functionality as the GWT DeckPanel + * {@link com.google.gwt.user.client.ui.DeckPanel}, with the exception that it + * doesn't manipulate the child widgets' width and height attributes. + */ +public class VTabsheetPanel extends ComplexPanel { + + private Widget visibleWidget; + private TouchScrollDelegate touchScrollDelegate; + + /** + * Creates an empty tabsheet panel. + */ + public VTabsheetPanel() { + setElement(DOM.createDiv()); + sinkEvents(Event.TOUCHEVENTS); + addDomHandler(new TouchStartHandler() { + public void onTouchStart(TouchStartEvent event) { + /* + * All container elements needs to be scrollable by one finger. + * Update the scrollable element list of touch delegate on each + * touch start. + */ + NodeList childNodes = getElement().getChildNodes(); + Element[] elements = new Element[childNodes.getLength()]; + for (int i = 0; i < elements.length; i++) { + elements[i] = (Element) childNodes.getItem(i); + } + getTouchScrollDelegate().setElements(elements); + getTouchScrollDelegate().onTouchStart(event); + } + }, TouchStartEvent.getType()); + } + + protected TouchScrollDelegate getTouchScrollDelegate() { + if (touchScrollDelegate == null) { + touchScrollDelegate = new TouchScrollDelegate(); + } + return touchScrollDelegate; + + } + + /** + * Adds the specified widget to the deck. + * + * @param w + * the widget to be added + */ + @Override + public void add(Widget w) { + Element el = createContainerElement(); + DOM.appendChild(getElement(), el); + super.add(w, el); + } + + private Element createContainerElement() { + Element el = DOM.createDiv(); + DOM.setStyleAttribute(el, "position", "absolute"); + DOM.setStyleAttribute(el, "overflow", "auto"); + hide(el); + return el; + } + + /** + * Gets the index of the currently-visible widget. + * + * @return the visible widget's index + */ + public int getVisibleWidget() { + return getWidgetIndex(visibleWidget); + } + + /** + * Inserts a widget before the specified index. + * + * @param w + * the widget to be inserted + * @param beforeIndex + * the index before which it will be inserted + * @throws IndexOutOfBoundsException + * if beforeIndex is out of range + */ + public void insert(Widget w, int beforeIndex) { + Element el = createContainerElement(); + DOM.insertChild(getElement(), el, beforeIndex); + super.insert(w, el, beforeIndex, false); + } + + @Override + public boolean remove(Widget w) { + Element child = w.getElement(); + Element parent = null; + if (child != null) { + parent = DOM.getParent(child); + } + final boolean removed = super.remove(w); + if (removed) { + if (visibleWidget == w) { + visibleWidget = null; + } + if (parent != null) { + DOM.removeChild(getElement(), parent); + } + } + return removed; + } + + /** + * Shows the widget at the specified index. This causes the currently- + * visible widget to be hidden. + * + * @param index + * the index of the widget to be shown + */ + public void showWidget(int index) { + checkIndexBoundsForAccess(index); + Widget newVisible = getWidget(index); + if (visibleWidget != newVisible) { + if (visibleWidget != null) { + hide(DOM.getParent(visibleWidget.getElement())); + } + visibleWidget = newVisible; + unHide(DOM.getParent(visibleWidget.getElement())); + } + } + + private void hide(Element e) { + DOM.setStyleAttribute(e, "visibility", "hidden"); + DOM.setStyleAttribute(e, "top", "-100000px"); + DOM.setStyleAttribute(e, "left", "-100000px"); + } + + private void unHide(Element e) { + DOM.setStyleAttribute(e, "top", "0px"); + DOM.setStyleAttribute(e, "left", "0px"); + DOM.setStyleAttribute(e, "visibility", ""); + } + + public void fixVisibleTabSize(int width, int height, int minWidth) { + if (visibleWidget == null) { + return; + } + + boolean dynamicHeight = false; + + if (height < 0) { + height = visibleWidget.getOffsetHeight(); + dynamicHeight = true; + } + if (width < 0) { + width = visibleWidget.getOffsetWidth(); + } + if (width < minWidth) { + width = minWidth; + } + + Element wrapperDiv = (Element) visibleWidget.getElement() + .getParentElement(); + + // width first + getElement().getStyle().setPropertyPx("width", width); + wrapperDiv.getStyle().setPropertyPx("width", width); + + if (dynamicHeight) { + // height of widget might have changed due wrapping + height = visibleWidget.getOffsetHeight(); + } + // v-tabsheet-tabsheetpanel height + getElement().getStyle().setPropertyPx("height", height); + + // widget wrapper height + wrapperDiv.getStyle().setPropertyPx("height", height); + runWebkitOverflowAutoFix(); + } + + public void runWebkitOverflowAutoFix() { + if (visibleWidget != null) { + Util.runWebkitOverflowAutoFix(DOM.getParent(visibleWidget + .getElement())); + } + + } + + public void replaceComponent(Widget oldComponent, Widget newComponent) { + boolean isVisible = (visibleWidget == oldComponent); + int widgetIndex = getWidgetIndex(oldComponent); + remove(oldComponent); + insert(newComponent, widgetIndex); + if (isVisible) { + showWidget(widgetIndex); + } + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java b/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java index cd09e24d67..c6107e3b0e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java @@ -1,79 +1,79 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.UIDL; - -/** - * This class represents a multiline textfield (textarea). - * - * TODO consider replacing this with a RichTextArea based implementation. IE - * does not support CSS height for textareas in Strict mode :-( - * - * @author Vaadin Ltd. - * - */ -public class VTextArea extends VTextField { - public static final String CLASSNAME = "v-textarea"; - - public VTextArea() { - super(DOM.createTextArea()); - setStyleName(CLASSNAME); - } - - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - // Call parent renderer explicitly - super.updateFromUIDL(uidl, client); - - if (uidl.hasAttribute("rows")) { - setRows(uidl.getIntAttribute("rows")); - } - - if (getMaxLength() >= 0) { - sinkEvents(Event.ONKEYUP); - } - } - - public void setRows(int rows) { - setRows(getElement(), rows); - } - - private native void setRows(Element e, int r) - /*-{ - try { - if(e.tagName.toLowerCase() == "textarea") - e.rows = r; - } catch (e) {} - }-*/; - - @Override - public void onBrowserEvent(Event event) { - if (getMaxLength() >= 0 && event.getTypeInt() == Event.ONKEYUP) { - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - if (getText().length() > getMaxLength()) { - setText(getText().substring(0, getMaxLength())); - } - } - }); - } - super.onBrowserEvent(event); - } - - @Override - public int getCursorPos() { - // This is needed so that TextBoxImplIE6 is used to return the correct - // position for old Internet Explorer versions where it has to be - // detected in a different way. - return getImpl().getTextAreaCursorPos(getElement()); - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Event; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.UIDL; + +/** + * This class represents a multiline textfield (textarea). + * + * TODO consider replacing this with a RichTextArea based implementation. IE + * does not support CSS height for textareas in Strict mode :-( + * + * @author Vaadin Ltd. + * + */ +public class VTextArea extends VTextField { + public static final String CLASSNAME = "v-textarea"; + + public VTextArea() { + super(DOM.createTextArea()); + setStyleName(CLASSNAME); + } + + @Override + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + // Call parent renderer explicitly + super.updateFromUIDL(uidl, client); + + if (uidl.hasAttribute("rows")) { + setRows(uidl.getIntAttribute("rows")); + } + + if (getMaxLength() >= 0) { + sinkEvents(Event.ONKEYUP); + } + } + + public void setRows(int rows) { + setRows(getElement(), rows); + } + + private native void setRows(Element e, int r) + /*-{ + try { + if(e.tagName.toLowerCase() == "textarea") + e.rows = r; + } catch (e) {} + }-*/; + + @Override + public void onBrowserEvent(Event event) { + if (getMaxLength() >= 0 && event.getTypeInt() == Event.ONKEYUP) { + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + if (getText().length() > getMaxLength()) { + setText(getText().substring(0, getMaxLength())); + } + } + }); + } + super.onBrowserEvent(event); + } + + @Override + public int getCursorPos() { + // This is needed so that TextBoxImplIE6 is used to return the correct + // position for old Internet Explorer versions where it has to be + // detected in a different way. + return getImpl().getTextAreaCursorPos(getElement()); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java index 1353915d01..b569dbc94e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java @@ -1,645 +1,645 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import com.google.gwt.dom.client.Style.Overflow; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.DoubleClickEvent; -import com.google.gwt.event.dom.client.DoubleClickHandler; -import com.google.gwt.event.dom.client.HasDoubleClickHandlers; -import com.google.gwt.event.dom.client.KeyCodes; -import com.google.gwt.event.dom.client.KeyDownEvent; -import com.google.gwt.event.dom.client.KeyDownHandler; -import com.google.gwt.event.dom.client.MouseDownEvent; -import com.google.gwt.event.dom.client.MouseDownHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.HTML; -import com.google.gwt.user.client.ui.ListBox; -import com.google.gwt.user.client.ui.Panel; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; - -public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler, - MouseDownHandler, DoubleClickHandler, SubPartAware { - - private static final String CLASSNAME = "v-select-twincol"; - public static final String ATTRIBUTE_LEFT_CAPTION = "lc"; - public static final String ATTRIBUTE_RIGHT_CAPTION = "rc"; - - private static final int VISIBLE_COUNT = 10; - - private static final int DEFAULT_COLUMN_COUNT = 10; - - private final DoubleClickListBox options; - - private final DoubleClickListBox selections; - - private FlowPanel captionWrapper; - - private HTML optionsCaption = null; - - private HTML selectionsCaption = null; - - private final VButton add; - - private final VButton remove; - - private final FlowPanel buttons; - - private final Panel panel; - - private boolean widthSet = false; - - /** - * A ListBox which catches double clicks - * - */ - public class DoubleClickListBox extends ListBox implements - HasDoubleClickHandlers { - public DoubleClickListBox(boolean isMultipleSelect) { - super(isMultipleSelect); - } - - public DoubleClickListBox() { - super(); - } - - @Override - public HandlerRegistration addDoubleClickHandler( - DoubleClickHandler handler) { - return addDomHandler(handler, DoubleClickEvent.getType()); - } - } - - public VTwinColSelect() { - super(CLASSNAME); - - captionWrapper = new FlowPanel(); - - options = new DoubleClickListBox(); - options.addClickHandler(this); - options.addDoubleClickHandler(this); - options.setVisibleItemCount(VISIBLE_COUNT); - options.setStyleName(CLASSNAME + "-options"); - - selections = new DoubleClickListBox(); - selections.addClickHandler(this); - selections.addDoubleClickHandler(this); - selections.setVisibleItemCount(VISIBLE_COUNT); - selections.setStyleName(CLASSNAME + "-selections"); - - buttons = new FlowPanel(); - buttons.setStyleName(CLASSNAME + "-buttons"); - add = new VButton(); - add.setText(">>"); - add.addClickHandler(this); - remove = new VButton(); - remove.setText("<<"); - remove.addClickHandler(this); - - panel = ((Panel) optionsContainer); - - panel.add(captionWrapper); - captionWrapper.getElement().getStyle().setOverflow(Overflow.HIDDEN); - // Hide until there actually is a caption to prevent IE from rendering - // extra empty space - captionWrapper.setVisible(false); - - panel.add(options); - buttons.add(add); - final HTML br = new HTML(""); - br.setStyleName(CLASSNAME + "-deco"); - buttons.add(br); - buttons.add(remove); - panel.add(buttons); - panel.add(selections); - - options.addKeyDownHandler(this); - options.addMouseDownHandler(this); - - selections.addMouseDownHandler(this); - selections.addKeyDownHandler(this); - } - - public HTML getOptionsCaption() { - if (optionsCaption == null) { - optionsCaption = new HTML(); - optionsCaption.setStyleName(CLASSNAME + "-caption-left"); - optionsCaption.getElement().getStyle() - .setFloat(com.google.gwt.dom.client.Style.Float.LEFT); - captionWrapper.add(optionsCaption); - } - - return optionsCaption; - } - - public HTML getSelectionsCaption() { - if (selectionsCaption == null) { - selectionsCaption = new HTML(); - selectionsCaption.setStyleName(CLASSNAME + "-caption-right"); - selectionsCaption.getElement().getStyle() - .setFloat(com.google.gwt.dom.client.Style.Float.RIGHT); - captionWrapper.add(selectionsCaption); - } - - return selectionsCaption; - } - - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - // Captions are updated before super call to ensure the widths are set - // correctly - if (!uidl.getBooleanAttribute("cached")) { - updateCaptions(uidl); - } - - super.updateFromUIDL(uidl, client); - } - - private void updateCaptions(UIDL uidl) { - String leftCaption = (uidl.hasAttribute(ATTRIBUTE_LEFT_CAPTION) ? uidl - .getStringAttribute(ATTRIBUTE_LEFT_CAPTION) : null); - String rightCaption = (uidl.hasAttribute(ATTRIBUTE_RIGHT_CAPTION) ? uidl - .getStringAttribute(ATTRIBUTE_RIGHT_CAPTION) : null); - - boolean hasCaptions = (leftCaption != null || rightCaption != null); - - if (leftCaption == null) { - removeOptionsCaption(); - } else { - getOptionsCaption().setText(leftCaption); - - } - - if (rightCaption == null) { - removeSelectionsCaption(); - } else { - getSelectionsCaption().setText(rightCaption); - } - - captionWrapper.setVisible(hasCaptions); - } - - private void removeOptionsCaption() { - if (optionsCaption == null) { - return; - } - - if (optionsCaption.getParent() != null) { - captionWrapper.remove(optionsCaption); - } - - optionsCaption = null; - } - - private void removeSelectionsCaption() { - if (selectionsCaption == null) { - return; - } - - if (selectionsCaption.getParent() != null) { - captionWrapper.remove(selectionsCaption); - } - - selectionsCaption = null; - } - - @Override - protected void buildOptions(UIDL uidl) { - final boolean enabled = !isDisabled() && !isReadonly(); - options.setMultipleSelect(isMultiselect()); - selections.setMultipleSelect(isMultiselect()); - options.setEnabled(enabled); - selections.setEnabled(enabled); - add.setEnabled(enabled); - remove.setEnabled(enabled); - options.clear(); - selections.clear(); - for (final Iterator i = uidl.getChildIterator(); i.hasNext();) { - final UIDL optionUidl = (UIDL) i.next(); - if (optionUidl.hasAttribute("selected")) { - selections.addItem(optionUidl.getStringAttribute("caption"), - optionUidl.getStringAttribute("key")); - } else { - options.addItem(optionUidl.getStringAttribute("caption"), - optionUidl.getStringAttribute("key")); - } - } - - int cols = -1; - if (getColumns() > 0) { - cols = getColumns(); - } else if (!widthSet) { - cols = DEFAULT_COLUMN_COUNT; - } - - if (cols >= 0) { - String colWidth = cols + "em"; - String containerWidth = (2 * cols + 4) + "em"; - // Caption wrapper width == optionsSelect + buttons + - // selectionsSelect - String captionWrapperWidth = (2 * cols + 4 - 0.5) + "em"; - - options.setWidth(colWidth); - if (optionsCaption != null) { - optionsCaption.setWidth(colWidth); - } - selections.setWidth(colWidth); - if (selectionsCaption != null) { - selectionsCaption.setWidth(colWidth); - } - buttons.setWidth("3.5em"); - optionsContainer.setWidth(containerWidth); - captionWrapper.setWidth(captionWrapperWidth); - } - if (getRows() > 0) { - options.setVisibleItemCount(getRows()); - selections.setVisibleItemCount(getRows()); - - } - - } - - @Override - protected String[] getSelectedItems() { - final ArrayList selectedItemKeys = new ArrayList(); - for (int i = 0; i < selections.getItemCount(); i++) { - selectedItemKeys.add(selections.getValue(i)); - } - return selectedItemKeys.toArray(new String[selectedItemKeys.size()]); - } - - private boolean[] getSelectionBitmap(ListBox listBox) { - final boolean[] selectedIndexes = new boolean[listBox.getItemCount()]; - for (int i = 0; i < listBox.getItemCount(); i++) { - if (listBox.isItemSelected(i)) { - selectedIndexes[i] = true; - } else { - selectedIndexes[i] = false; - } - } - return selectedIndexes; - } - - private void addItem() { - Set movedItems = moveSelectedItems(options, selections); - selectedKeys.addAll(movedItems); - - client.updateVariable(id, "selected", - selectedKeys.toArray(new String[selectedKeys.size()]), - isImmediate()); - } - - private void removeItem() { - Set movedItems = moveSelectedItems(selections, options); - selectedKeys.removeAll(movedItems); - - client.updateVariable(id, "selected", - selectedKeys.toArray(new String[selectedKeys.size()]), - isImmediate()); - } - - private Set moveSelectedItems(ListBox source, ListBox target) { - final boolean[] sel = getSelectionBitmap(source); - final Set movedItems = new HashSet(); - int lastSelected = 0; - for (int i = 0; i < sel.length; i++) { - if (sel[i]) { - final int optionIndex = i - - (sel.length - source.getItemCount()); - movedItems.add(source.getValue(optionIndex)); - - // Move selection to another column - final String text = source.getItemText(optionIndex); - final String value = source.getValue(optionIndex); - target.addItem(text, value); - target.setItemSelected(target.getItemCount() - 1, true); - source.removeItem(optionIndex); - - if (source.getItemCount() > 0) { - lastSelected = optionIndex > 0 ? optionIndex - 1 : 0; - } - } - } - - if (source.getItemCount() > 0) { - source.setSelectedIndex(lastSelected); - } - - // If no items are left move the focus to the selections - if (source.getItemCount() == 0) { - target.setFocus(true); - } else { - source.setFocus(true); - } - - return movedItems; - } - - @Override - public void onClick(ClickEvent event) { - super.onClick(event); - if (event.getSource() == add) { - addItem(); - - } else if (event.getSource() == remove) { - removeItem(); - - } else if (event.getSource() == options) { - // unselect all in other list, to avoid mistakes (i.e wrong button) - final int c = selections.getItemCount(); - for (int i = 0; i < c; i++) { - selections.setItemSelected(i, false); - } - } else if (event.getSource() == selections) { - // unselect all in other list, to avoid mistakes (i.e wrong button) - final int c = options.getItemCount(); - for (int i = 0; i < c; i++) { - options.setItemSelected(i, false); - } - } - } - - @Override - public void setHeight(String height) { - super.setHeight(height); - if ("".equals(height)) { - options.setHeight(""); - selections.setHeight(""); - } else { - setInternalHeights(); - } - } - - private void setInternalHeights() { - int captionHeight = 0; - int totalHeight; - if (BrowserInfo.get().isIE6()) { - String o = getElement().getStyle().getOverflow(); - - getElement().getStyle().setOverflow(Overflow.HIDDEN); - totalHeight = getOffsetHeight(); - getElement().getStyle().setProperty("overflow", o); - } else { - totalHeight = getOffsetHeight(); - } - - if (optionsCaption != null) { - captionHeight = Util.getRequiredHeight(optionsCaption); - } else if (selectionsCaption != null) { - captionHeight = Util.getRequiredHeight(selectionsCaption); - } - String selectHeight = (totalHeight - captionHeight) + "px"; - - selections.setHeight(selectHeight); - options.setHeight(selectHeight); - - } - - @Override - public void setWidth(String width) { - super.setWidth(width); - if (!"".equals(width) && width != null) { - setInternalWidths(); - widthSet = true; - } else { - widthSet = false; - } - } - - private void setInternalWidths() { - DOM.setStyleAttribute(getElement(), "position", "relative"); - int bordersAndPaddings = Util.measureHorizontalPaddingAndBorder( - buttons.getElement(), 0); - - if (BrowserInfo.get().isIE6()) { - // IE6 sets a border on selects by default.. - bordersAndPaddings += 4; - } - - int buttonWidth = Util.getRequiredWidth(buttons); - int totalWidth = getOffsetWidth(); - - int spaceForSelect = (totalWidth - buttonWidth - bordersAndPaddings) / 2; - - options.setWidth(spaceForSelect + "px"); - if (optionsCaption != null) { - optionsCaption.setWidth(spaceForSelect + "px"); - } - - selections.setWidth(spaceForSelect + "px"); - if (selectionsCaption != null) { - selectionsCaption.setWidth(spaceForSelect + "px"); - } - captionWrapper.setWidth("100%"); - } - - @Override - protected void setTabIndex(int tabIndex) { - options.setTabIndex(tabIndex); - selections.setTabIndex(tabIndex); - add.setTabIndex(tabIndex); - remove.setTabIndex(tabIndex); - } - - public void focus() { - options.setFocus(true); - } - - /** - * Get the key that selects an item in the table. By default it is the Enter - * key but by overriding this you can change the key to whatever you want. - * - * @return - */ - protected int getNavigationSelectKey() { - return KeyCodes.KEY_ENTER; - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.KeyDownHandler#onKeyDown(com.google.gwt - * .event.dom.client.KeyDownEvent) - */ - public void onKeyDown(KeyDownEvent event) { - int keycode = event.getNativeKeyCode(); - - // Catch tab and move between select:s - if (keycode == KeyCodes.KEY_TAB && event.getSource() == options) { - // Prevent default behavior - event.preventDefault(); - - // Remove current selections - for (int i = 0; i < options.getItemCount(); i++) { - options.setItemSelected(i, false); - } - - // Focus selections - selections.setFocus(true); - } - - if (keycode == KeyCodes.KEY_TAB && event.isShiftKeyDown() - && event.getSource() == selections) { - // Prevent default behavior - event.preventDefault(); - - // Remove current selections - for (int i = 0; i < selections.getItemCount(); i++) { - selections.setItemSelected(i, false); - } - - // Focus options - options.setFocus(true); - } - - if (keycode == getNavigationSelectKey()) { - // Prevent default behavior - event.preventDefault(); - - // Decide which select the selection was made in - if (event.getSource() == options) { - // Prevents the selection to become a single selection when - // using Enter key - // as the selection key (default) - options.setFocus(false); - - addItem(); - - } else if (event.getSource() == selections) { - // Prevents the selection to become a single selection when - // using Enter key - // as the selection key (default) - selections.setFocus(false); - - removeItem(); - } - } - - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.MouseDownHandler#onMouseDown(com.google - * .gwt.event.dom.client.MouseDownEvent) - */ - public void onMouseDown(MouseDownEvent event) { - // Ensure that items are deselected when selecting - // from a different source. See #3699 for details. - if (event.getSource() == options) { - for (int i = 0; i < selections.getItemCount(); i++) { - selections.setItemSelected(i, false); - } - } else if (event.getSource() == selections) { - for (int i = 0; i < options.getItemCount(); i++) { - options.setItemSelected(i, false); - } - } - - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.DoubleClickHandler#onDoubleClick(com. - * google.gwt.event.dom.client.DoubleClickEvent) - */ - public void onDoubleClick(DoubleClickEvent event) { - if (event.getSource() == options) { - addItem(); - options.setSelectedIndex(-1); - options.setFocus(false); - } else if (event.getSource() == selections) { - removeItem(); - selections.setSelectedIndex(-1); - selections.setFocus(false); - } - - } - - private static final String SUBPART_OPTION_SELECT = "leftSelect"; - private static final String SUBPART_OPTION_SELECT_ITEM = SUBPART_OPTION_SELECT - + "-item"; - private static final String SUBPART_SELECTION_SELECT = "rightSelect"; - private static final String SUBPART_SELECTION_SELECT_ITEM = SUBPART_SELECTION_SELECT - + "-item"; - private static final String SUBPART_LEFT_CAPTION = "leftCaption"; - private static final String SUBPART_RIGHT_CAPTION = "rightCaption"; - private static final String SUBPART_ADD_BUTTON = "add"; - private static final String SUBPART_REMOVE_BUTTON = "remove"; - - public Element getSubPartElement(String subPart) { - if (SUBPART_OPTION_SELECT.equals(subPart)) { - return options.getElement(); - } else if (subPart.startsWith(SUBPART_OPTION_SELECT_ITEM)) { - String idx = subPart.substring(SUBPART_OPTION_SELECT_ITEM.length()); - return (Element) options.getElement().getChild( - Integer.parseInt(idx)); - } else if (SUBPART_SELECTION_SELECT.equals(subPart)) { - return selections.getElement(); - } else if (subPart.startsWith(SUBPART_SELECTION_SELECT_ITEM)) { - String idx = subPart.substring(SUBPART_SELECTION_SELECT_ITEM - .length()); - return (Element) selections.getElement().getChild( - Integer.parseInt(idx)); - } else if (optionsCaption != null - && SUBPART_LEFT_CAPTION.equals(subPart)) { - return optionsCaption.getElement(); - } else if (selectionsCaption != null - && SUBPART_RIGHT_CAPTION.equals(subPart)) { - return selectionsCaption.getElement(); - } else if (SUBPART_ADD_BUTTON.equals(subPart)) { - return add.getElement(); - } else if (SUBPART_REMOVE_BUTTON.equals(subPart)) { - return remove.getElement(); - } - - return null; - } - - public String getSubPartName(Element subElement) { - if (optionsCaption != null - && optionsCaption.getElement().isOrHasChild(subElement)) { - return SUBPART_LEFT_CAPTION; - } else if (selectionsCaption != null - && selectionsCaption.getElement().isOrHasChild(subElement)) { - return SUBPART_RIGHT_CAPTION; - } else if (options.getElement().isOrHasChild(subElement)) { - if (options.getElement() == subElement) { - return SUBPART_OPTION_SELECT; - } else { - int idx = Util.getChildElementIndex(subElement); - return SUBPART_OPTION_SELECT_ITEM + idx; - } - } else if (selections.getElement().isOrHasChild(subElement)) { - if (selections.getElement() == subElement) { - return SUBPART_SELECTION_SELECT; - } else { - int idx = Util.getChildElementIndex(subElement); - return SUBPART_SELECTION_SELECT_ITEM + idx; - } - } else if (add.getElement().isOrHasChild(subElement)) { - return SUBPART_ADD_BUTTON; - } else if (remove.getElement().isOrHasChild(subElement)) { - return SUBPART_REMOVE_BUTTON; - } - - return null; - } -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.google.gwt.dom.client.Style.Overflow; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.DoubleClickEvent; +import com.google.gwt.event.dom.client.DoubleClickHandler; +import com.google.gwt.event.dom.client.HasDoubleClickHandlers; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.event.dom.client.KeyDownEvent; +import com.google.gwt.event.dom.client.KeyDownHandler; +import com.google.gwt.event.dom.client.MouseDownEvent; +import com.google.gwt.event.dom.client.MouseDownHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.Panel; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; + +public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler, + MouseDownHandler, DoubleClickHandler, SubPartAware { + + private static final String CLASSNAME = "v-select-twincol"; + public static final String ATTRIBUTE_LEFT_CAPTION = "lc"; + public static final String ATTRIBUTE_RIGHT_CAPTION = "rc"; + + private static final int VISIBLE_COUNT = 10; + + private static final int DEFAULT_COLUMN_COUNT = 10; + + private final DoubleClickListBox options; + + private final DoubleClickListBox selections; + + private FlowPanel captionWrapper; + + private HTML optionsCaption = null; + + private HTML selectionsCaption = null; + + private final VButton add; + + private final VButton remove; + + private final FlowPanel buttons; + + private final Panel panel; + + private boolean widthSet = false; + + /** + * A ListBox which catches double clicks + * + */ + public class DoubleClickListBox extends ListBox implements + HasDoubleClickHandlers { + public DoubleClickListBox(boolean isMultipleSelect) { + super(isMultipleSelect); + } + + public DoubleClickListBox() { + super(); + } + + @Override + public HandlerRegistration addDoubleClickHandler( + DoubleClickHandler handler) { + return addDomHandler(handler, DoubleClickEvent.getType()); + } + } + + public VTwinColSelect() { + super(CLASSNAME); + + captionWrapper = new FlowPanel(); + + options = new DoubleClickListBox(); + options.addClickHandler(this); + options.addDoubleClickHandler(this); + options.setVisibleItemCount(VISIBLE_COUNT); + options.setStyleName(CLASSNAME + "-options"); + + selections = new DoubleClickListBox(); + selections.addClickHandler(this); + selections.addDoubleClickHandler(this); + selections.setVisibleItemCount(VISIBLE_COUNT); + selections.setStyleName(CLASSNAME + "-selections"); + + buttons = new FlowPanel(); + buttons.setStyleName(CLASSNAME + "-buttons"); + add = new VButton(); + add.setText(">>"); + add.addClickHandler(this); + remove = new VButton(); + remove.setText("<<"); + remove.addClickHandler(this); + + panel = ((Panel) optionsContainer); + + panel.add(captionWrapper); + captionWrapper.getElement().getStyle().setOverflow(Overflow.HIDDEN); + // Hide until there actually is a caption to prevent IE from rendering + // extra empty space + captionWrapper.setVisible(false); + + panel.add(options); + buttons.add(add); + final HTML br = new HTML(""); + br.setStyleName(CLASSNAME + "-deco"); + buttons.add(br); + buttons.add(remove); + panel.add(buttons); + panel.add(selections); + + options.addKeyDownHandler(this); + options.addMouseDownHandler(this); + + selections.addMouseDownHandler(this); + selections.addKeyDownHandler(this); + } + + public HTML getOptionsCaption() { + if (optionsCaption == null) { + optionsCaption = new HTML(); + optionsCaption.setStyleName(CLASSNAME + "-caption-left"); + optionsCaption.getElement().getStyle() + .setFloat(com.google.gwt.dom.client.Style.Float.LEFT); + captionWrapper.add(optionsCaption); + } + + return optionsCaption; + } + + public HTML getSelectionsCaption() { + if (selectionsCaption == null) { + selectionsCaption = new HTML(); + selectionsCaption.setStyleName(CLASSNAME + "-caption-right"); + selectionsCaption.getElement().getStyle() + .setFloat(com.google.gwt.dom.client.Style.Float.RIGHT); + captionWrapper.add(selectionsCaption); + } + + return selectionsCaption; + } + + @Override + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + // Captions are updated before super call to ensure the widths are set + // correctly + if (!uidl.getBooleanAttribute("cached")) { + updateCaptions(uidl); + } + + super.updateFromUIDL(uidl, client); + } + + private void updateCaptions(UIDL uidl) { + String leftCaption = (uidl.hasAttribute(ATTRIBUTE_LEFT_CAPTION) ? uidl + .getStringAttribute(ATTRIBUTE_LEFT_CAPTION) : null); + String rightCaption = (uidl.hasAttribute(ATTRIBUTE_RIGHT_CAPTION) ? uidl + .getStringAttribute(ATTRIBUTE_RIGHT_CAPTION) : null); + + boolean hasCaptions = (leftCaption != null || rightCaption != null); + + if (leftCaption == null) { + removeOptionsCaption(); + } else { + getOptionsCaption().setText(leftCaption); + + } + + if (rightCaption == null) { + removeSelectionsCaption(); + } else { + getSelectionsCaption().setText(rightCaption); + } + + captionWrapper.setVisible(hasCaptions); + } + + private void removeOptionsCaption() { + if (optionsCaption == null) { + return; + } + + if (optionsCaption.getParent() != null) { + captionWrapper.remove(optionsCaption); + } + + optionsCaption = null; + } + + private void removeSelectionsCaption() { + if (selectionsCaption == null) { + return; + } + + if (selectionsCaption.getParent() != null) { + captionWrapper.remove(selectionsCaption); + } + + selectionsCaption = null; + } + + @Override + protected void buildOptions(UIDL uidl) { + final boolean enabled = !isDisabled() && !isReadonly(); + options.setMultipleSelect(isMultiselect()); + selections.setMultipleSelect(isMultiselect()); + options.setEnabled(enabled); + selections.setEnabled(enabled); + add.setEnabled(enabled); + remove.setEnabled(enabled); + options.clear(); + selections.clear(); + for (final Iterator i = uidl.getChildIterator(); i.hasNext();) { + final UIDL optionUidl = (UIDL) i.next(); + if (optionUidl.hasAttribute("selected")) { + selections.addItem(optionUidl.getStringAttribute("caption"), + optionUidl.getStringAttribute("key")); + } else { + options.addItem(optionUidl.getStringAttribute("caption"), + optionUidl.getStringAttribute("key")); + } + } + + int cols = -1; + if (getColumns() > 0) { + cols = getColumns(); + } else if (!widthSet) { + cols = DEFAULT_COLUMN_COUNT; + } + + if (cols >= 0) { + String colWidth = cols + "em"; + String containerWidth = (2 * cols + 4) + "em"; + // Caption wrapper width == optionsSelect + buttons + + // selectionsSelect + String captionWrapperWidth = (2 * cols + 4 - 0.5) + "em"; + + options.setWidth(colWidth); + if (optionsCaption != null) { + optionsCaption.setWidth(colWidth); + } + selections.setWidth(colWidth); + if (selectionsCaption != null) { + selectionsCaption.setWidth(colWidth); + } + buttons.setWidth("3.5em"); + optionsContainer.setWidth(containerWidth); + captionWrapper.setWidth(captionWrapperWidth); + } + if (getRows() > 0) { + options.setVisibleItemCount(getRows()); + selections.setVisibleItemCount(getRows()); + + } + + } + + @Override + protected String[] getSelectedItems() { + final ArrayList selectedItemKeys = new ArrayList(); + for (int i = 0; i < selections.getItemCount(); i++) { + selectedItemKeys.add(selections.getValue(i)); + } + return selectedItemKeys.toArray(new String[selectedItemKeys.size()]); + } + + private boolean[] getSelectionBitmap(ListBox listBox) { + final boolean[] selectedIndexes = new boolean[listBox.getItemCount()]; + for (int i = 0; i < listBox.getItemCount(); i++) { + if (listBox.isItemSelected(i)) { + selectedIndexes[i] = true; + } else { + selectedIndexes[i] = false; + } + } + return selectedIndexes; + } + + private void addItem() { + Set movedItems = moveSelectedItems(options, selections); + selectedKeys.addAll(movedItems); + + client.updateVariable(id, "selected", + selectedKeys.toArray(new String[selectedKeys.size()]), + isImmediate()); + } + + private void removeItem() { + Set movedItems = moveSelectedItems(selections, options); + selectedKeys.removeAll(movedItems); + + client.updateVariable(id, "selected", + selectedKeys.toArray(new String[selectedKeys.size()]), + isImmediate()); + } + + private Set moveSelectedItems(ListBox source, ListBox target) { + final boolean[] sel = getSelectionBitmap(source); + final Set movedItems = new HashSet(); + int lastSelected = 0; + for (int i = 0; i < sel.length; i++) { + if (sel[i]) { + final int optionIndex = i + - (sel.length - source.getItemCount()); + movedItems.add(source.getValue(optionIndex)); + + // Move selection to another column + final String text = source.getItemText(optionIndex); + final String value = source.getValue(optionIndex); + target.addItem(text, value); + target.setItemSelected(target.getItemCount() - 1, true); + source.removeItem(optionIndex); + + if (source.getItemCount() > 0) { + lastSelected = optionIndex > 0 ? optionIndex - 1 : 0; + } + } + } + + if (source.getItemCount() > 0) { + source.setSelectedIndex(lastSelected); + } + + // If no items are left move the focus to the selections + if (source.getItemCount() == 0) { + target.setFocus(true); + } else { + source.setFocus(true); + } + + return movedItems; + } + + @Override + public void onClick(ClickEvent event) { + super.onClick(event); + if (event.getSource() == add) { + addItem(); + + } else if (event.getSource() == remove) { + removeItem(); + + } else if (event.getSource() == options) { + // unselect all in other list, to avoid mistakes (i.e wrong button) + final int c = selections.getItemCount(); + for (int i = 0; i < c; i++) { + selections.setItemSelected(i, false); + } + } else if (event.getSource() == selections) { + // unselect all in other list, to avoid mistakes (i.e wrong button) + final int c = options.getItemCount(); + for (int i = 0; i < c; i++) { + options.setItemSelected(i, false); + } + } + } + + @Override + public void setHeight(String height) { + super.setHeight(height); + if ("".equals(height)) { + options.setHeight(""); + selections.setHeight(""); + } else { + setInternalHeights(); + } + } + + private void setInternalHeights() { + int captionHeight = 0; + int totalHeight; + if (BrowserInfo.get().isIE6()) { + String o = getElement().getStyle().getOverflow(); + + getElement().getStyle().setOverflow(Overflow.HIDDEN); + totalHeight = getOffsetHeight(); + getElement().getStyle().setProperty("overflow", o); + } else { + totalHeight = getOffsetHeight(); + } + + if (optionsCaption != null) { + captionHeight = Util.getRequiredHeight(optionsCaption); + } else if (selectionsCaption != null) { + captionHeight = Util.getRequiredHeight(selectionsCaption); + } + String selectHeight = (totalHeight - captionHeight) + "px"; + + selections.setHeight(selectHeight); + options.setHeight(selectHeight); + + } + + @Override + public void setWidth(String width) { + super.setWidth(width); + if (!"".equals(width) && width != null) { + setInternalWidths(); + widthSet = true; + } else { + widthSet = false; + } + } + + private void setInternalWidths() { + DOM.setStyleAttribute(getElement(), "position", "relative"); + int bordersAndPaddings = Util.measureHorizontalPaddingAndBorder( + buttons.getElement(), 0); + + if (BrowserInfo.get().isIE6()) { + // IE6 sets a border on selects by default.. + bordersAndPaddings += 4; + } + + int buttonWidth = Util.getRequiredWidth(buttons); + int totalWidth = getOffsetWidth(); + + int spaceForSelect = (totalWidth - buttonWidth - bordersAndPaddings) / 2; + + options.setWidth(spaceForSelect + "px"); + if (optionsCaption != null) { + optionsCaption.setWidth(spaceForSelect + "px"); + } + + selections.setWidth(spaceForSelect + "px"); + if (selectionsCaption != null) { + selectionsCaption.setWidth(spaceForSelect + "px"); + } + captionWrapper.setWidth("100%"); + } + + @Override + protected void setTabIndex(int tabIndex) { + options.setTabIndex(tabIndex); + selections.setTabIndex(tabIndex); + add.setTabIndex(tabIndex); + remove.setTabIndex(tabIndex); + } + + public void focus() { + options.setFocus(true); + } + + /** + * Get the key that selects an item in the table. By default it is the Enter + * key but by overriding this you can change the key to whatever you want. + * + * @return + */ + protected int getNavigationSelectKey() { + return KeyCodes.KEY_ENTER; + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.KeyDownHandler#onKeyDown(com.google.gwt + * .event.dom.client.KeyDownEvent) + */ + public void onKeyDown(KeyDownEvent event) { + int keycode = event.getNativeKeyCode(); + + // Catch tab and move between select:s + if (keycode == KeyCodes.KEY_TAB && event.getSource() == options) { + // Prevent default behavior + event.preventDefault(); + + // Remove current selections + for (int i = 0; i < options.getItemCount(); i++) { + options.setItemSelected(i, false); + } + + // Focus selections + selections.setFocus(true); + } + + if (keycode == KeyCodes.KEY_TAB && event.isShiftKeyDown() + && event.getSource() == selections) { + // Prevent default behavior + event.preventDefault(); + + // Remove current selections + for (int i = 0; i < selections.getItemCount(); i++) { + selections.setItemSelected(i, false); + } + + // Focus options + options.setFocus(true); + } + + if (keycode == getNavigationSelectKey()) { + // Prevent default behavior + event.preventDefault(); + + // Decide which select the selection was made in + if (event.getSource() == options) { + // Prevents the selection to become a single selection when + // using Enter key + // as the selection key (default) + options.setFocus(false); + + addItem(); + + } else if (event.getSource() == selections) { + // Prevents the selection to become a single selection when + // using Enter key + // as the selection key (default) + selections.setFocus(false); + + removeItem(); + } + } + + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.MouseDownHandler#onMouseDown(com.google + * .gwt.event.dom.client.MouseDownEvent) + */ + public void onMouseDown(MouseDownEvent event) { + // Ensure that items are deselected when selecting + // from a different source. See #3699 for details. + if (event.getSource() == options) { + for (int i = 0; i < selections.getItemCount(); i++) { + selections.setItemSelected(i, false); + } + } else if (event.getSource() == selections) { + for (int i = 0; i < options.getItemCount(); i++) { + options.setItemSelected(i, false); + } + } + + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.DoubleClickHandler#onDoubleClick(com. + * google.gwt.event.dom.client.DoubleClickEvent) + */ + public void onDoubleClick(DoubleClickEvent event) { + if (event.getSource() == options) { + addItem(); + options.setSelectedIndex(-1); + options.setFocus(false); + } else if (event.getSource() == selections) { + removeItem(); + selections.setSelectedIndex(-1); + selections.setFocus(false); + } + + } + + private static final String SUBPART_OPTION_SELECT = "leftSelect"; + private static final String SUBPART_OPTION_SELECT_ITEM = SUBPART_OPTION_SELECT + + "-item"; + private static final String SUBPART_SELECTION_SELECT = "rightSelect"; + private static final String SUBPART_SELECTION_SELECT_ITEM = SUBPART_SELECTION_SELECT + + "-item"; + private static final String SUBPART_LEFT_CAPTION = "leftCaption"; + private static final String SUBPART_RIGHT_CAPTION = "rightCaption"; + private static final String SUBPART_ADD_BUTTON = "add"; + private static final String SUBPART_REMOVE_BUTTON = "remove"; + + public Element getSubPartElement(String subPart) { + if (SUBPART_OPTION_SELECT.equals(subPart)) { + return options.getElement(); + } else if (subPart.startsWith(SUBPART_OPTION_SELECT_ITEM)) { + String idx = subPart.substring(SUBPART_OPTION_SELECT_ITEM.length()); + return (Element) options.getElement().getChild( + Integer.parseInt(idx)); + } else if (SUBPART_SELECTION_SELECT.equals(subPart)) { + return selections.getElement(); + } else if (subPart.startsWith(SUBPART_SELECTION_SELECT_ITEM)) { + String idx = subPart.substring(SUBPART_SELECTION_SELECT_ITEM + .length()); + return (Element) selections.getElement().getChild( + Integer.parseInt(idx)); + } else if (optionsCaption != null + && SUBPART_LEFT_CAPTION.equals(subPart)) { + return optionsCaption.getElement(); + } else if (selectionsCaption != null + && SUBPART_RIGHT_CAPTION.equals(subPart)) { + return selectionsCaption.getElement(); + } else if (SUBPART_ADD_BUTTON.equals(subPart)) { + return add.getElement(); + } else if (SUBPART_REMOVE_BUTTON.equals(subPart)) { + return remove.getElement(); + } + + return null; + } + + public String getSubPartName(Element subElement) { + if (optionsCaption != null + && optionsCaption.getElement().isOrHasChild(subElement)) { + return SUBPART_LEFT_CAPTION; + } else if (selectionsCaption != null + && selectionsCaption.getElement().isOrHasChild(subElement)) { + return SUBPART_RIGHT_CAPTION; + } else if (options.getElement().isOrHasChild(subElement)) { + if (options.getElement() == subElement) { + return SUBPART_OPTION_SELECT; + } else { + int idx = Util.getChildElementIndex(subElement); + return SUBPART_OPTION_SELECT_ITEM + idx; + } + } else if (selections.getElement().isOrHasChild(subElement)) { + if (selections.getElement() == subElement) { + return SUBPART_SELECTION_SELECT; + } else { + int idx = Util.getChildElementIndex(subElement); + return SUBPART_SELECTION_SELECT_ITEM + idx; + } + } else if (add.getElement().isOrHasChild(subElement)) { + return SUBPART_ADD_BUTTON; + } else if (remove.getElement().isOrHasChild(subElement)) { + return SUBPART_REMOVE_BUTTON; + } + + return null; + } +} diff --git a/src/com/vaadin/ui/ComboBox.java b/src/com/vaadin/ui/ComboBox.java index 0fb8b9d873..bc7ab6f994 100644 --- a/src/com/vaadin/ui/ComboBox.java +++ b/src/com/vaadin/ui/ComboBox.java @@ -1,129 +1,129 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Collection; - -import com.vaadin.data.Container; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VFilterSelect; - -/** - * A filtering dropdown single-select. Suitable for newItemsAllowed, but it's - * turned of by default to avoid mistakes. Items are filtered based on user - * input, and loaded dynamically ("lazy-loading") from the server. You can turn - * on newItemsAllowed and change filtering mode (and also turn it off), but you - * can not turn on multi-select mode. - * - */ -@SuppressWarnings("serial") -@ClientWidget(VFilterSelect.class) -public class ComboBox extends Select { - - private String inputPrompt = null; - - /** - * If text input is not allowed, the ComboBox behaves like a pretty - * NativeSelect - the user can not enter any text and clicking the text - * field opens the drop down with options - */ - private boolean textInputAllowed = true; - - public ComboBox() { - setMultiSelect(false); - setNewItemsAllowed(false); - } - - public ComboBox(String caption, Collection options) { - super(caption, options); - setMultiSelect(false); - setNewItemsAllowed(false); - } - - public ComboBox(String caption, Container dataSource) { - super(caption, dataSource); - setMultiSelect(false); - setNewItemsAllowed(false); - } - - public ComboBox(String caption) { - super(caption); - setMultiSelect(false); - setNewItemsAllowed(false); - } - - @Override - public void setMultiSelect(boolean multiSelect) { - if (multiSelect && !isMultiSelect()) { - throw new UnsupportedOperationException("Multiselect not supported"); - } - super.setMultiSelect(multiSelect); - } - - /** - * Gets the current input prompt. - * - * @see #setInputPrompt(String) - * @return the current input prompt, or null if not enabled - */ - public String getInputPrompt() { - return inputPrompt; - } - - /** - * Sets the input prompt - a textual prompt that is displayed when the - * select would otherwise be empty, to prompt the user for input. - * - * @param inputPrompt - * the desired input prompt, or null to disable - */ - public void setInputPrompt(String inputPrompt) { - this.inputPrompt = inputPrompt; - requestRepaint(); - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - if (inputPrompt != null) { - target.addAttribute("prompt", inputPrompt); - } - super.paintContent(target); - - if (!textInputAllowed) { - target.addAttribute(VFilterSelect.ATTR_NO_TEXT_INPUT, true); - } - } - - /** - * Sets whether it is possible to input text into the field or whether the - * field area of the component is just used to show what is selected. By - * disabling text input, the comboBox will work in the same way as a - * {@link NativeSelect} - * - * @see #isTextInputAllowed() - * - * @param textInputAllowed - * true to allow entering text, false to just show the current - * selection - */ - public void setTextInputAllowed(boolean textInputAllowed) { - this.textInputAllowed = textInputAllowed; - requestRepaint(); - } - - /** - * Returns true if the user can enter text into the field to either filter - * the selections or enter a new value if {@link #isNewItemsAllowed()} - * returns true. If text input is disabled, the comboBox will work in the - * same way as a {@link NativeSelect} - * - * @return - */ - public boolean isTextInputAllowed() { - return textInputAllowed; - } - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.ui; + +import java.util.Collection; + +import com.vaadin.data.Container; +import com.vaadin.terminal.PaintException; +import com.vaadin.terminal.PaintTarget; +import com.vaadin.terminal.gwt.client.ui.VFilterSelect; + +/** + * A filtering dropdown single-select. Suitable for newItemsAllowed, but it's + * turned of by default to avoid mistakes. Items are filtered based on user + * input, and loaded dynamically ("lazy-loading") from the server. You can turn + * on newItemsAllowed and change filtering mode (and also turn it off), but you + * can not turn on multi-select mode. + * + */ +@SuppressWarnings("serial") +@ClientWidget(VFilterSelect.class) +public class ComboBox extends Select { + + private String inputPrompt = null; + + /** + * If text input is not allowed, the ComboBox behaves like a pretty + * NativeSelect - the user can not enter any text and clicking the text + * field opens the drop down with options + */ + private boolean textInputAllowed = true; + + public ComboBox() { + setMultiSelect(false); + setNewItemsAllowed(false); + } + + public ComboBox(String caption, Collection options) { + super(caption, options); + setMultiSelect(false); + setNewItemsAllowed(false); + } + + public ComboBox(String caption, Container dataSource) { + super(caption, dataSource); + setMultiSelect(false); + setNewItemsAllowed(false); + } + + public ComboBox(String caption) { + super(caption); + setMultiSelect(false); + setNewItemsAllowed(false); + } + + @Override + public void setMultiSelect(boolean multiSelect) { + if (multiSelect && !isMultiSelect()) { + throw new UnsupportedOperationException("Multiselect not supported"); + } + super.setMultiSelect(multiSelect); + } + + /** + * Gets the current input prompt. + * + * @see #setInputPrompt(String) + * @return the current input prompt, or null if not enabled + */ + public String getInputPrompt() { + return inputPrompt; + } + + /** + * Sets the input prompt - a textual prompt that is displayed when the + * select would otherwise be empty, to prompt the user for input. + * + * @param inputPrompt + * the desired input prompt, or null to disable + */ + public void setInputPrompt(String inputPrompt) { + this.inputPrompt = inputPrompt; + requestRepaint(); + } + + @Override + public void paintContent(PaintTarget target) throws PaintException { + if (inputPrompt != null) { + target.addAttribute("prompt", inputPrompt); + } + super.paintContent(target); + + if (!textInputAllowed) { + target.addAttribute(VFilterSelect.ATTR_NO_TEXT_INPUT, true); + } + } + + /** + * Sets whether it is possible to input text into the field or whether the + * field area of the component is just used to show what is selected. By + * disabling text input, the comboBox will work in the same way as a + * {@link NativeSelect} + * + * @see #isTextInputAllowed() + * + * @param textInputAllowed + * true to allow entering text, false to just show the current + * selection + */ + public void setTextInputAllowed(boolean textInputAllowed) { + this.textInputAllowed = textInputAllowed; + requestRepaint(); + } + + /** + * Returns true if the user can enter text into the field to either filter + * the selections or enter a new value if {@link #isNewItemsAllowed()} + * returns true. If text input is disabled, the comboBox will work in the + * same way as a {@link NativeSelect} + * + * @return + */ + public boolean isTextInputAllowed() { + return textInputAllowed; + } + +} diff --git a/src/com/vaadin/ui/InlineDateField.java b/src/com/vaadin/ui/InlineDateField.java index 0bf7924d34..50e16d803b 100644 --- a/src/com/vaadin/ui/InlineDateField.java +++ b/src/com/vaadin/ui/InlineDateField.java @@ -1,48 +1,48 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Date; - -import com.vaadin.data.Property; -import com.vaadin.terminal.gwt.client.ui.VDateFieldCalendar; - -/** - *

- * A date entry component, which displays the actual date selector inline. - * - *

- * - * @see DateField - * @see PopupDateField - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ -@ClientWidget(VDateFieldCalendar.class) -public class InlineDateField extends DateField { - - public InlineDateField() { - super(); - } - - public InlineDateField(Property dataSource) throws IllegalArgumentException { - super(dataSource); - } - - public InlineDateField(String caption, Date value) { - super(caption, value); - } - - public InlineDateField(String caption, Property dataSource) { - super(caption, dataSource); - } - - public InlineDateField(String caption) { - super(caption); - } - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.ui; + +import java.util.Date; + +import com.vaadin.data.Property; +import com.vaadin.terminal.gwt.client.ui.VDateFieldCalendar; + +/** + *

+ * A date entry component, which displays the actual date selector inline. + * + *

+ * + * @see DateField + * @see PopupDateField + * @author Vaadin Ltd. + * @version + * @VERSION@ + * @since 5.0 + */ +@ClientWidget(VDateFieldCalendar.class) +public class InlineDateField extends DateField { + + public InlineDateField() { + super(); + } + + public InlineDateField(Property dataSource) throws IllegalArgumentException { + super(dataSource); + } + + public InlineDateField(String caption, Date value) { + super(caption, value); + } + + public InlineDateField(String caption, Property dataSource) { + super(caption, dataSource); + } + + public InlineDateField(String caption) { + super(caption); + } + +} diff --git a/src/com/vaadin/ui/PopupDateField.java b/src/com/vaadin/ui/PopupDateField.java index d25608a4c4..3688d4035f 100644 --- a/src/com/vaadin/ui/PopupDateField.java +++ b/src/com/vaadin/ui/PopupDateField.java @@ -1,80 +1,80 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Date; - -import com.vaadin.data.Property; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; - -/** - *

- * A date entry component, which displays the actual date selector as a popup. - * - *

- * - * @see DateField - * @see InlineDateField - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ -public class PopupDateField extends DateField { - - private String inputPrompt = null; - - public PopupDateField() { - super(); - } - - public PopupDateField(Property dataSource) throws IllegalArgumentException { - super(dataSource); - } - - public PopupDateField(String caption, Date value) { - super(caption, value); - } - - public PopupDateField(String caption, Property dataSource) { - super(caption, dataSource); - } - - public PopupDateField(String caption) { - super(caption); - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - - if (inputPrompt != null) { - target.addAttribute("prompt", inputPrompt); - } - } - - /** - * Gets the current input prompt. - * - * @see #setInputPrompt(String) - * @return the current input prompt, or null if not enabled - */ - public String getInputPrompt() { - return inputPrompt; - } - - /** - * Sets the input prompt - a textual prompt that is displayed when the field - * would otherwise be empty, to prompt the user for input. - * - * @param inputPrompt - */ - public void setInputPrompt(String inputPrompt) { - this.inputPrompt = inputPrompt; - requestRepaint(); - } - -} +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.ui; + +import java.util.Date; + +import com.vaadin.data.Property; +import com.vaadin.terminal.PaintException; +import com.vaadin.terminal.PaintTarget; + +/** + *

+ * A date entry component, which displays the actual date selector as a popup. + * + *

+ * + * @see DateField + * @see InlineDateField + * @author Vaadin Ltd. + * @version + * @VERSION@ + * @since 5.0 + */ +public class PopupDateField extends DateField { + + private String inputPrompt = null; + + public PopupDateField() { + super(); + } + + public PopupDateField(Property dataSource) throws IllegalArgumentException { + super(dataSource); + } + + public PopupDateField(String caption, Date value) { + super(caption, value); + } + + public PopupDateField(String caption, Property dataSource) { + super(caption, dataSource); + } + + public PopupDateField(String caption) { + super(caption); + } + + @Override + public void paintContent(PaintTarget target) throws PaintException { + super.paintContent(target); + + if (inputPrompt != null) { + target.addAttribute("prompt", inputPrompt); + } + } + + /** + * Gets the current input prompt. + * + * @see #setInputPrompt(String) + * @return the current input prompt, or null if not enabled + */ + public String getInputPrompt() { + return inputPrompt; + } + + /** + * Sets the input prompt - a textual prompt that is displayed when the field + * would otherwise be empty, to prompt the user for input. + * + * @param inputPrompt + */ + public void setInputPrompt(String inputPrompt) { + this.inputPrompt = inputPrompt; + requestRepaint(); + } + +} -- cgit v1.2.3 From 116cd1f29a432fe5ca64f3023a9fec1ca130f078 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 27 Jan 2012 14:17:02 +0000 Subject: #8311 Additional CRLF->LF fixes svn changeset:22799/svn branch:6.8 --- .../terminal/gwt/client/ui/VCalendarPanel.java | 219 ++++++++++----------- src/com/vaadin/terminal/gwt/client/ui/VSlider.java | 4 - .../abstractorderedlayout/AddComponentsTest.java | 8 +- .../component/csslayout/AddComponentsTest.java | 2 +- .../AbstractIndexedLayoutTest.java | 168 ++++++++-------- .../tests/application/WebBrowserSizeTest.java | 90 ++++----- .../vaadin/tests/application/WebBrowserTest.java | 2 +- .../datefield/PopupDateFieldExtendedRange.java | 138 ++++++------- 8 files changed, 311 insertions(+), 320 deletions(-) (limited to 'src/com') diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java index e35bd93f67..a2f03d6176 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java @@ -72,7 +72,7 @@ public class VCalendarPanel extends FocusableFlexTable implements /** * FocusChangeListener is notified when the panel changes its _focused_ - * value. It can be set with + * value. */ public interface FocusChangeListener { void focusChanged(Date focusedDate); @@ -103,6 +103,8 @@ public class VCalendarPanel extends FocusableFlexTable implements private static final String CN_SELECTED = "selected"; + private static final String CN_OFFMONTH = "offmonth"; + /** * Represents a click handler for when a user selects a value by using the * mouse @@ -117,7 +119,7 @@ public class VCalendarPanel extends FocusableFlexTable implements */ public void onClick(ClickEvent event) { Day day = (Day) event.getSource(); - focusDay(day.getDay()); + focusDay(day.getDate()); selectFocused(); onSubmit(); } @@ -151,6 +153,8 @@ public class VCalendarPanel extends FocusableFlexTable implements private boolean showISOWeekNumbers; + private Date displayedMonth; + private Date focusedDate; private Day selectedDay; @@ -187,21 +191,22 @@ public class VCalendarPanel extends FocusableFlexTable implements } /** - * Sets the focus to given day of current time. Used when moving in the - * calender with the keyboard. + * Sets the focus to given date in the current view. Used when moving in the + * calendar with the keyboard. * - * @param day - * The day number from by Date.getDate() + * @param date + * A Date representing the day of month to be focused. Must be + * one of the days currently visible. */ - private void focusDay(int day) { + private void focusDay(Date date) { // Only used when calender body is present if (resolution > VDateField.RESOLUTION_MONTH) { if (focusedDay != null) { focusedDay.removeStyleDependentName(CN_FOCUSED); } - if (day > 0 && focusedDate != null) { - focusedDate.setDate(day); + if (date != null && focusedDate != null) { + focusedDate.setTime(date.getTime()); int rowCount = days.getRowCount(); for (int i = 0; i < rowCount; i++) { int cellCount = days.getCellCount(i); @@ -209,7 +214,7 @@ public class VCalendarPanel extends FocusableFlexTable implements Widget widget = days.getWidget(i, j); if (widget != null && widget instanceof Day) { Day curday = (Day) widget; - if (curday.getDay() == day) { + if (curday.getDate().equals(date)) { curday.addStyleDependentName(CN_FOCUSED); focusedDay = curday; focusedRow = i; @@ -223,11 +228,14 @@ public class VCalendarPanel extends FocusableFlexTable implements } /** - * Sets the selection hightlight to a given date of current time + * Sets the selection highlight to a given day in the current view + * + * @param date + * A Date representing the day of month to be selected. Must be + * one of the days currently visible. * - * @param day */ - private void selectDate(int day) { + private void selectDate(Date date) { if (selectedDay != null) { selectedDay.removeStyleDependentName(CN_SELECTED); } @@ -239,7 +247,7 @@ public class VCalendarPanel extends FocusableFlexTable implements Widget widget = days.getWidget(i, j); if (widget != null && widget instanceof Day) { Day curday = (Day) widget; - if (curday.getDay() == day) { + if (curday.getDate().equals(date)) { curday.addStyleDependentName(CN_SELECTED); selectedDay = curday; return; @@ -278,7 +286,7 @@ public class VCalendarPanel extends FocusableFlexTable implements // it was forced to 1 above. value.setDate(focusedDate.getDate()); - selectDate(focusedDate.getDate()); + selectDate(focusedDate); } else { VConsole.log("Trying to select a the focused date which is NULL!"); } @@ -467,97 +475,62 @@ public class VCalendarPanel extends FocusableFlexTable implements } } - // The day of month that is selected, -1 if no day of this month is - // selected (i.e, showing another month/year than selected or nothing is - // selected) - int dayOfMonthSelected = -1; - // The day of month that is today, -1 if no day of this month is today - // (i.e., showing another month/year than current) - int dayOfMonthToday = -1; - - boolean initiallyNull = value == null; - - if (!initiallyNull && value.getMonth() == focusedDate.getMonth() - && value.getYear() == focusedDate.getYear()) { - dayOfMonthSelected = value.getDate(); - } - final Date today = new Date(); - if (today.getMonth() == focusedDate.getMonth() - && today.getYear() == focusedDate.getYear()) { - dayOfMonthToday = today.getDate(); - } + // today must have zeroed hours, minutes, seconds, and milliseconds + final Date tmp = new Date(); + final Date today = new Date(tmp.getYear(), tmp.getMonth(), + tmp.getDate()); final int startWeekDay = getDateTimeService().getStartWeekDay( focusedDate); - final int daysInMonth = DateTimeService - .getNumberOfDaysInMonth(focusedDate); - - int dayCount = 0; - final Date curr = new Date(focusedDate.getTime()); + final Date curr = (Date) focusedDate.clone(); + // Start from the first day of the week that at least partially belongs + // to the current month + curr.setDate(-startWeekDay); // No month has more than 6 weeks so 6 is a safe maximum for rows. for (int weekOfMonth = 1; weekOfMonth < 7; weekOfMonth++) { - boolean weekNumberProcessed[] = new boolean[] { false, false, - false, false, false, false, false }; - for (int dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) { - if (!(weekOfMonth == 1 && dayOfWeek < startWeekDay)) { - - if (dayCount >= daysInMonth) { - // All days printed and we are done - break; - } - - final int dayOfMonth = ++dayCount; - - curr.setDate(dayCount); - // Actually write the day of month - Day day = new Day(dayOfMonth); + // Actually write the day of month + Day day = new Day((Date) curr.clone()); - if (dayOfMonthSelected == dayOfMonth) { - day.addStyleDependentName(CN_SELECTED); - selectedDay = day; + if (curr.equals(value)) { + day.addStyleDependentName(CN_SELECTED); + selectedDay = day; + } + if (curr.equals(today)) { + day.addStyleDependentName(CN_TODAY); + } + if (curr.equals(focusedDate)) { + focusedDay = day; + focusedRow = weekOfMonth; + if (hasFocus) { + day.addStyleDependentName(CN_FOCUSED); } + } + if (curr.getMonth() != focusedDate.getMonth()) { + day.addStyleDependentName(CN_OFFMONTH); + } - if (dayOfMonthToday == dayOfMonth) { - day.addStyleDependentName(CN_TODAY); - } + days.setWidget(weekOfMonth, firstWeekdayColumn + dayOfWeek, day); - if (dayOfMonth == focusedDate.getDate()) { - focusedDay = day; - focusedRow = weekOfMonth; - if (hasFocus) { - day.addStyleDependentName(CN_FOCUSED); - } - } + // ISO week numbers if requested + days.getCellFormatter().setVisible(weekOfMonth, weekColumn, + isShowISOWeekNumbers()); + if (isShowISOWeekNumbers()) { + final String baseCssClass = VDateField.CLASSNAME + + "-calendarpanel-weeknumber"; + String weekCssClass = baseCssClass; - days.setWidget(weekOfMonth, firstWeekdayColumn + dayOfWeek, - day); - - // ISO week numbers if requested - if (!weekNumberProcessed[weekOfMonth]) { - days.getCellFormatter().setVisible(weekOfMonth, - weekColumn, isShowISOWeekNumbers()); - if (isShowISOWeekNumbers()) { - final String baseCssClass = VDateField.CLASSNAME - + "-calendarpanel-weeknumber"; - String weekCssClass = baseCssClass; - - int weekNumber = DateTimeService - .getISOWeekNumber(curr); - - days.setHTML(weekOfMonth, 0, "" + weekNumber - + ""); - weekNumberProcessed[weekOfMonth] = true; - } + int weekNumber = DateTimeService.getISOWeekNumber(curr); - } + days.setHTML(weekOfMonth, 0, "" + weekNumber + + ""); } + curr.setDate(curr.getDate() + 1); } } - } /** @@ -621,6 +594,7 @@ public class VCalendarPanel extends FocusableFlexTable implements while (focusedDate.getMonth() != requestedMonth) { focusedDate.setDate(focusedDate.getDate() - 1); } + displayedMonth.setMonth(displayedMonth.getMonth() + 1); renderCalendar(); } @@ -640,6 +614,7 @@ public class VCalendarPanel extends FocusableFlexTable implements while (focusedDate.getMonth() == currentMonth) { focusedDate.setDate(focusedDate.getDate() - 1); } + displayedMonth.setMonth(displayedMonth.getMonth() - 1); renderCalendar(); } @@ -649,6 +624,7 @@ public class VCalendarPanel extends FocusableFlexTable implements */ private void focusPreviousYear(int years) { focusedDate.setYear(focusedDate.getYear() - years); + displayedMonth.setYear(displayedMonth.getYear() - years); renderCalendar(); } @@ -657,6 +633,7 @@ public class VCalendarPanel extends FocusableFlexTable implements */ private void focusNextYear(int years) { focusedDate.setYear(focusedDate.getYear() + years); + displayedMonth.setYear(displayedMonth.getYear() + years); renderCalendar(); } @@ -905,7 +882,7 @@ public class VCalendarPanel extends FocusableFlexTable implements if (newCurrentDate.getMonth() == focusedDate.getMonth()) { // Month did not change, only move the selection - focusDay(focusedDate.getDate() + 1); + focusDay(newCurrentDate); } else { // If the month changed we need to re-render the calendar focusedDate.setDate(focusedDate.getDate() + 1); @@ -924,7 +901,7 @@ public class VCalendarPanel extends FocusableFlexTable implements if (newCurrentDate.getMonth() == focusedDate.getMonth()) { // Month did not change, only move the selection - focusDay(focusedDate.getDate() - 1); + focusDay(newCurrentDate); } else { // If the month changed we need to re-render the calendar focusedDate.setDate(focusedDate.getDate() - 1); @@ -944,10 +921,10 @@ public class VCalendarPanel extends FocusableFlexTable implements if (newCurrentDate.getMonth() == focusedDate.getMonth() && focusedRow > 1) { // Month did not change, only move the selection - focusDay(focusedDate.getDate() - 7); + focusDay(newCurrentDate); } else { // If the month changed we need to re-render the calendar - focusedDate.setDate(focusedDate.getDate() - 7); + focusedDate = newCurrentDate; renderCalendar(); } @@ -963,10 +940,10 @@ public class VCalendarPanel extends FocusableFlexTable implements if (newCurrentDate.getMonth() == focusedDate.getMonth()) { // Month did not change, only move the selection - focusDay(focusedDate.getDate() + 7); + focusDay(newCurrentDate); } else { // If the month changed we need to re-render the calendar - focusedDate.setDate(focusedDate.getDate() + 7); + focusedDate = newCurrentDate; renderCalendar(); } @@ -1210,27 +1187,28 @@ public class VCalendarPanel extends FocusableFlexTable implements return; } - Date oldFocusedValue = focusedDate; + Date oldDisplayedMonth = displayedMonth; value = currentDate; if (value == null) { - focusedDate = null; + focusedDate = displayedMonth = null; } else { focusedDate = (Date) value.clone(); + displayedMonth = (Date) value.clone(); } // Re-render calendar if month or year of focused date has changed - if (oldFocusedValue == null || value == null - || oldFocusedValue.getYear() != value.getYear() - || oldFocusedValue.getMonth() != value.getMonth()) { + if (oldDisplayedMonth == null || value == null + || oldDisplayedMonth.getYear() != value.getYear() + || oldDisplayedMonth.getMonth() != value.getMonth()) { renderCalendar(); } else { - focusDay(currentDate.getDate()); + focusDay(currentDate); selectFocused(); } if (!hasFocus) { - focusDay(-1); + focusDay((Date) null); } } @@ -1552,20 +1530,23 @@ public class VCalendarPanel extends FocusableFlexTable implements } + /** + * A widget representing a single day in the calendar panel. + */ private class Day extends InlineHTML { private static final String BASECLASS = VDateField.CLASSNAME + "-calendarpanel-day"; - private final int day; + private final Date date; - Day(int dayOfMonth) { - super("" + dayOfMonth); + Day(Date date) { + super("" + date.getDate()); setStyleName(BASECLASS); - day = dayOfMonth; + this.date = date; addClickHandler(dayClickHandler); } - public int getDay() { - return day; + public Date getDate() { + return date; } } @@ -1648,7 +1629,7 @@ public class VCalendarPanel extends FocusableFlexTable implements public void onBlur(final BlurEvent event) { if (event.getSource() instanceof VCalendarPanel) { hasFocus = false; - focusDay(-1); + focusDay(null); } } @@ -1665,7 +1646,7 @@ public class VCalendarPanel extends FocusableFlexTable implements // Focuses the current day if the calendar shows the days if (focusedDay != null) { - focusDay(focusedDay.getDay()); + focusDay(focusedDate); } } } @@ -1696,7 +1677,17 @@ public class VCalendarPanel extends FocusableFlexTable implements // Day, find out which dayOfMonth and use that as the identifier Day day = Util.findWidget(subElement, Day.class); if (day != null) { - return SUBPART_DAY + day.getDay(); + Date date = day.getDate(); + int id = date.getDate(); + // Zero or negative ids map to days of the preceding month, + // past-the-end-of-month ids to days of the following month + if (date.getMonth() < displayedMonth.getMonth()) { + id -= DateTimeService.getNumberOfDaysInMonth(date); + } else if (date.getMonth() > displayedMonth.getMonth()) { + id += DateTimeService + .getNumberOfDaysInMonth(displayedMonth); + } + return SUBPART_DAY + id; } } else if (time != null) { if (contains(time.hours, subElement)) { @@ -1762,14 +1753,18 @@ public class VCalendarPanel extends FocusableFlexTable implements return time.ampm.getElement(); } if (subPart.startsWith(SUBPART_DAY)) { + // Zero or negative ids map to days in the preceding month, + // past-the-end-of-month ids to days in the following month int dayOfMonth = Integer.parseInt(subPart.substring(SUBPART_DAY .length())); + Date date = new Date(displayedMonth.getYear(), + displayedMonth.getMonth(), dayOfMonth); Iterator iter = days.iterator(); while (iter.hasNext()) { Widget w = iter.next(); if (w instanceof Day) { Day day = (Day) w; - if (day.getDay() == dayOfMonth) { + if (day.getDate().equals(date)) { return day.getElement(); } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSlider.java b/src/com/vaadin/terminal/gwt/client/ui/VSlider.java index a001ca7f13..4a46346613 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VSlider.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VSlider.java @@ -425,10 +425,6 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field, setValueByEvent(event, true); DOM.eventCancelBubble(event, true); } - } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN && dragging) { - dragging = false; - DOM.releaseCapture(getElement()); - setValueByEvent(event, true); } } diff --git a/tests/server-side/com/vaadin/tests/server/component/abstractorderedlayout/AddComponentsTest.java b/tests/server-side/com/vaadin/tests/server/component/abstractorderedlayout/AddComponentsTest.java index bd67841f33..1971fb6d0e 100644 --- a/tests/server-side/com/vaadin/tests/server/component/abstractorderedlayout/AddComponentsTest.java +++ b/tests/server-side/com/vaadin/tests/server/component/abstractorderedlayout/AddComponentsTest.java @@ -1,14 +1,14 @@ package com.vaadin.tests.server.component.abstractorderedlayout; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.fail; - import java.util.Iterator; import java.util.NoSuchElementException; import org.junit.Test; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; + import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Component; import com.vaadin.ui.HorizontalLayout; diff --git a/tests/server-side/com/vaadin/tests/server/component/csslayout/AddComponentsTest.java b/tests/server-side/com/vaadin/tests/server/component/csslayout/AddComponentsTest.java index d4a0592768..c0d739b597 100644 --- a/tests/server-side/com/vaadin/tests/server/component/csslayout/AddComponentsTest.java +++ b/tests/server-side/com/vaadin/tests/server/component/csslayout/AddComponentsTest.java @@ -5,8 +5,8 @@ import java.util.NoSuchElementException; import org.junit.Test; -import static org.junit.Assert.assertSame; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import com.vaadin.ui.Component; diff --git a/tests/server-side/com/vaadin/tests/server/componentcontainer/AbstractIndexedLayoutTest.java b/tests/server-side/com/vaadin/tests/server/componentcontainer/AbstractIndexedLayoutTest.java index 9271e9f1b3..e3e743d02a 100644 --- a/tests/server-side/com/vaadin/tests/server/componentcontainer/AbstractIndexedLayoutTest.java +++ b/tests/server-side/com/vaadin/tests/server/componentcontainer/AbstractIndexedLayoutTest.java @@ -1,84 +1,84 @@ -package com.vaadin.tests.server.componentcontainer; - -import junit.framework.TestCase; - -import com.vaadin.ui.Component; -import com.vaadin.ui.Label; -import com.vaadin.ui.Layout; - -public abstract class AbstractIndexedLayoutTest extends TestCase { - - private Layout layout; - - protected abstract Layout createLayout(); - - @Override - protected void setUp() throws Exception { - layout = createLayout(); - } - - public Layout getLayout() { - return layout; - } - - public void testAddRemoveComponent() { - Label c1 = new Label(); - Label c2 = new Label(); - - layout.addComponent(c1); - - assertEquals(c1, getComponent(0)); - assertEquals(1, getComponentCount()); - layout.addComponent(c2); - assertEquals(c1, getComponent(0)); - assertEquals(c2, getComponent(1)); - assertEquals(2, getComponentCount()); - layout.removeComponent(c1); - assertEquals(c2, getComponent(0)); - assertEquals(1, getComponentCount()); - layout.removeComponent(c2); - assertEquals(0, getComponentCount()); - } - - protected abstract int getComponentCount(); - - protected abstract Component getComponent(int index); - - protected abstract int getComponentIndex(Component c); - - public void testGetComponentIndex() { - Label c1 = new Label(); - Label c2 = new Label(); - - layout.addComponent(c1); - assertEquals(0, getComponentIndex(c1)); - layout.addComponent(c2); - assertEquals(0, getComponentIndex(c1)); - assertEquals(1, getComponentIndex(c2)); - layout.removeComponent(c1); - assertEquals(0, getComponentIndex(c2)); - layout.removeComponent(c2); - assertEquals(-1, getComponentIndex(c2)); - assertEquals(-1, getComponentIndex(c1)); - } - - public void testGetComponent() { - Label c1 = new Label(); - Label c2 = new Label(); - - layout.addComponent(c1); - assertEquals(c1, getComponent(0)); - layout.addComponent(c2); - assertEquals(c1, getComponent(0)); - assertEquals(c2, getComponent(1)); - layout.removeComponent(c1); - assertEquals(c2, getComponent(0)); - layout.removeComponent(c2); - try { - getComponent(0); - fail(); - } catch (IndexOutOfBoundsException e) { - // Expected - } - } -} +package com.vaadin.tests.server.componentcontainer; + +import junit.framework.TestCase; + +import com.vaadin.ui.Component; +import com.vaadin.ui.Label; +import com.vaadin.ui.Layout; + +public abstract class AbstractIndexedLayoutTest extends TestCase { + + private Layout layout; + + protected abstract Layout createLayout(); + + @Override + protected void setUp() throws Exception { + layout = createLayout(); + } + + public Layout getLayout() { + return layout; + } + + public void testAddRemoveComponent() { + Label c1 = new Label(); + Label c2 = new Label(); + + layout.addComponent(c1); + + assertEquals(c1, getComponent(0)); + assertEquals(1, getComponentCount()); + layout.addComponent(c2); + assertEquals(c1, getComponent(0)); + assertEquals(c2, getComponent(1)); + assertEquals(2, getComponentCount()); + layout.removeComponent(c1); + assertEquals(c2, getComponent(0)); + assertEquals(1, getComponentCount()); + layout.removeComponent(c2); + assertEquals(0, getComponentCount()); + } + + protected abstract int getComponentCount(); + + protected abstract Component getComponent(int index); + + protected abstract int getComponentIndex(Component c); + + public void testGetComponentIndex() { + Label c1 = new Label(); + Label c2 = new Label(); + + layout.addComponent(c1); + assertEquals(0, getComponentIndex(c1)); + layout.addComponent(c2); + assertEquals(0, getComponentIndex(c1)); + assertEquals(1, getComponentIndex(c2)); + layout.removeComponent(c1); + assertEquals(0, getComponentIndex(c2)); + layout.removeComponent(c2); + assertEquals(-1, getComponentIndex(c2)); + assertEquals(-1, getComponentIndex(c1)); + } + + public void testGetComponent() { + Label c1 = new Label(); + Label c2 = new Label(); + + layout.addComponent(c1); + assertEquals(c1, getComponent(0)); + layout.addComponent(c2); + assertEquals(c1, getComponent(0)); + assertEquals(c2, getComponent(1)); + layout.removeComponent(c1); + assertEquals(c2, getComponent(0)); + layout.removeComponent(c2); + try { + getComponent(0); + fail(); + } catch (IndexOutOfBoundsException e) { + // Expected + } + } +} diff --git a/tests/testbench/com/vaadin/tests/application/WebBrowserSizeTest.java b/tests/testbench/com/vaadin/tests/application/WebBrowserSizeTest.java index f2726118d4..eacf2a0e53 100644 --- a/tests/testbench/com/vaadin/tests/application/WebBrowserSizeTest.java +++ b/tests/testbench/com/vaadin/tests/application/WebBrowserSizeTest.java @@ -1,45 +1,45 @@ -package com.vaadin.tests.application; - -import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Label; - -public class WebBrowserSizeTest extends TestBase { - - @Override - protected void setup() { - - final Label screenSizeLabel = new Label("n/a"); - screenSizeLabel.setCaption("Screen size"); - - final Label browserSizeLabel = new Label("n/a"); - browserSizeLabel.setCaption("Client (browser window) size"); - - final Button update = new Button("Refresh", new Button.ClickListener() { - - public void buttonClick(ClickEvent event) { - screenSizeLabel.setValue(getBrowser().getScreenWidth() + " x " - + getBrowser().getScreenHeight()); - browserSizeLabel.setValue(getBrowser().getClientWidth() + " x " - + getBrowser().getClientHeight()); - } - }); - - addComponent(update); - addComponent(screenSizeLabel); - addComponent(browserSizeLabel); - - } - - @Override - protected String getDescription() { - return "Verifies that browser sizes are reported correctly. Note that client width differs depending on browser decorations."; - } - - @Override - protected Integer getTicketNumber() { - return 5655; - } - -} +package com.vaadin.tests.application; + +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Label; + +public class WebBrowserSizeTest extends TestBase { + + @Override + protected void setup() { + + final Label screenSizeLabel = new Label("n/a"); + screenSizeLabel.setCaption("Screen size"); + + final Label browserSizeLabel = new Label("n/a"); + browserSizeLabel.setCaption("Client (browser window) size"); + + final Button update = new Button("Refresh", new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + screenSizeLabel.setValue(getBrowser().getScreenWidth() + " x " + + getBrowser().getScreenHeight()); + browserSizeLabel.setValue(getBrowser().getClientWidth() + " x " + + getBrowser().getClientHeight()); + } + }); + + addComponent(update); + addComponent(screenSizeLabel); + addComponent(browserSizeLabel); + + } + + @Override + protected String getDescription() { + return "Verifies that browser sizes are reported correctly. Note that client width differs depending on browser decorations."; + } + + @Override + protected Integer getTicketNumber() { + return 5655; + } + +} diff --git a/tests/testbench/com/vaadin/tests/application/WebBrowserTest.java b/tests/testbench/com/vaadin/tests/application/WebBrowserTest.java index 4508e4ef90..35235bbe1f 100644 --- a/tests/testbench/com/vaadin/tests/application/WebBrowserTest.java +++ b/tests/testbench/com/vaadin/tests/application/WebBrowserTest.java @@ -71,6 +71,7 @@ public class WebBrowserTest extends TestBase { curDateLabel.setValue(getBrowser().getCurrentDate() .toString()); + } }); @@ -82,7 +83,6 @@ public class WebBrowserTest extends TestBase { addComponent(curDateLabel); addComponent(diffLabel); addComponent(containsLabel); - } @Override diff --git a/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldExtendedRange.java b/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldExtendedRange.java index 4fc8f87398..357c61f4f6 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldExtendedRange.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldExtendedRange.java @@ -1,69 +1,69 @@ -package com.vaadin.tests.components.datefield; - -import java.util.Calendar; -import java.util.Locale; - -import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Button.ClickListener; -import com.vaadin.ui.DateField; -import com.vaadin.ui.PopupDateField; - -@SuppressWarnings("serial") -public class PopupDateFieldExtendedRange extends TestBase { - - private Calendar date = Calendar.getInstance(); - - @Override - protected void setup() { - date.set(2011, 0, 1); - - getLayout().setSpacing(true); - - final PopupDateField[] fields = new PopupDateField[3]; - - fields[0] = makeDateField(); - fields[0].setLocale(new Locale("fi", "FI")); - fields[0].setCaption("Finnish locale"); - - fields[1] = makeDateField(); - fields[1].setLocale(new Locale("en", "US")); - fields[1].setCaption("US English locale"); - - fields[2] = makeDateField(); - fields[2].setLocale(new Locale("fi", "FI")); - fields[2].setShowISOWeekNumbers(true); - fields[2].setCaption("Finnish locale with week numbers"); - - for (PopupDateField f : fields) { - addComponent(f); - } - - addComponent(new Button("Change date", new ClickListener() { - public void buttonClick(ClickEvent event) { - date.set(2010, 1, 16); - for (PopupDateField f : fields) { - f.setValue(date.getTime()); - } - } - })); - } - - @Override - protected String getDescription() { - return "Show a few days of the preceding and following months in the datefield popup"; - } - - @Override - protected Integer getTicketNumber() { - return 6718; - } - - private PopupDateField makeDateField() { - PopupDateField pdf = new PopupDateField(); - pdf.setResolution(DateField.RESOLUTION_DAY); - pdf.setValue(date.getTime()); - return pdf; - } -} +package com.vaadin.tests.components.datefield; + +import java.util.Calendar; +import java.util.Locale; + +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.DateField; +import com.vaadin.ui.PopupDateField; + +@SuppressWarnings("serial") +public class PopupDateFieldExtendedRange extends TestBase { + + private Calendar date = Calendar.getInstance(); + + @Override + protected void setup() { + date.set(2011, 0, 1); + + getLayout().setSpacing(true); + + final PopupDateField[] fields = new PopupDateField[3]; + + fields[0] = makeDateField(); + fields[0].setLocale(new Locale("fi", "FI")); + fields[0].setCaption("Finnish locale"); + + fields[1] = makeDateField(); + fields[1].setLocale(new Locale("en", "US")); + fields[1].setCaption("US English locale"); + + fields[2] = makeDateField(); + fields[2].setLocale(new Locale("fi", "FI")); + fields[2].setShowISOWeekNumbers(true); + fields[2].setCaption("Finnish locale with week numbers"); + + for (PopupDateField f : fields) { + addComponent(f); + } + + addComponent(new Button("Change date", new ClickListener() { + public void buttonClick(ClickEvent event) { + date.set(2010, 1, 16); + for (PopupDateField f : fields) { + f.setValue(date.getTime()); + } + } + })); + } + + @Override + protected String getDescription() { + return "Show a few days of the preceding and following months in the datefield popup"; + } + + @Override + protected Integer getTicketNumber() { + return 6718; + } + + private PopupDateField makeDateField() { + PopupDateField pdf = new PopupDateField(); + pdf.setResolution(DateField.RESOLUTION_DAY); + pdf.setValue(date.getTime()); + return pdf; + } +} -- cgit v1.2.3