aboutsummaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
authorMatti Tahvonen <matti.tahvonen@itmill.com>2010-03-05 13:43:43 +0000
committerMatti Tahvonen <matti.tahvonen@itmill.com>2010-03-05 13:43:43 +0000
commit7cefe21c703e6e7822ba7456d45fa49a14dd067d (patch)
tree8891e28e97bce4f9db44dd7f50cbb6a844de8aef /src/com
parent9b84a02d3f46d1f4dca4cc3b17c388d51ca5194a (diff)
parent2b1deeeced6d098a22d6e52b70e94dbb9e96df57 (diff)
downloadvaadin-framework-7cefe21c703e6e7822ba7456d45fa49a14dd067d.tar.gz
vaadin-framework-7cefe21c703e6e7822ba7456d45fa49a14dd067d.zip
merged changes from 6.3 + some container related changes
svn changeset:11664/svn branch:6.3_dd
Diffstat (limited to 'src/com')
-rw-r--r--src/com/vaadin/Application.java106
-rw-r--r--src/com/vaadin/data/Container.java18
-rw-r--r--src/com/vaadin/data/util/BeanItemContainer.java127
-rw-r--r--src/com/vaadin/data/util/ContainerHierarchicalWrapper.java13
-rw-r--r--src/com/vaadin/data/util/HierarchicalContainer.java312
-rw-r--r--src/com/vaadin/data/util/IndexedContainer.java29
-rw-r--r--src/com/vaadin/data/util/ListSet.java198
-rw-r--r--src/com/vaadin/terminal/FileResource.java11
-rw-r--r--src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java19
-rwxr-xr-xsrc/com/vaadin/terminal/gwt/client/ApplicationConnection.java20
-rw-r--r--src/com/vaadin/terminal/gwt/client/ClientExceptionHandler.java2
-rw-r--r--src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java9
-rwxr-xr-xsrc/com/vaadin/terminal/gwt/client/VDebugConsole.java22
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java9
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java11
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java19
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java16
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java36
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VPanel.java8
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java7
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java11
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java71
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTextField.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VView.java10
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java605
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java83
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java14
-rw-r--r--src/com/vaadin/terminal/gwt/server/CommunicationManager.java12
-rw-r--r--src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java26
-rw-r--r--src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java71
-rw-r--r--src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java16
-rw-r--r--src/com/vaadin/ui/Button.java8
-rw-r--r--src/com/vaadin/ui/Form.java97
-rw-r--r--src/com/vaadin/ui/Panel.java12
-rw-r--r--src/com/vaadin/ui/SplitPanel.java14
-rw-r--r--src/com/vaadin/ui/Table.java20
-rw-r--r--src/com/vaadin/ui/Tree.java39
-rw-r--r--src/com/vaadin/ui/Window.java45
-rw-r--r--src/com/vaadin/ui/themes/BaseTheme.java44
-rw-r--r--src/com/vaadin/ui/themes/Reindeer.java163
-rw-r--r--src/com/vaadin/ui/themes/Runo.java30
41 files changed, 1875 insertions, 509 deletions
diff --git a/src/com/vaadin/Application.java b/src/com/vaadin/Application.java
index 67bc5e9da6..9a0c180a1d 100644
--- a/src/com/vaadin/Application.java
+++ b/src/com/vaadin/Application.java
@@ -1303,6 +1303,13 @@ public abstract class Application implements URIHandler,
* <li><b>outOfSyncMessage</b> = "Something has caused us to be out of sync
* with the server.<br/>
* Take note of any unsaved data, and <u>click here</u> to re-sync."</li>
+ * <li><b>cookiesDisabledURL</b> = null</li>
+ * <li><b>cookiesDisabledNotificationEnabled</b> = true</li>
+ * <li><b>cookiesDisabledCaption</b> = "Cookies disabled"</li>
+ * <li><b>cookiesDisabledMessage</b> = "This application requires cookies to
+ * function.<br/>
+ * Please enable cookies in your browser and <u>click here</u> to try again.
+ * </li>
* </ul>
* </p>
*
@@ -1328,6 +1335,11 @@ public abstract class Application implements URIHandler,
protected String outOfSyncCaption = "Out of sync";
protected String outOfSyncMessage = "Something has caused us to be out of sync with the server.<br/>Take note of any unsaved data, and <u>click here</u> to re-sync.";
+ protected String cookiesDisabledURL = null;
+ protected boolean cookiesDisabledNotificationEnabled = true;
+ protected String cookiesDisabledCaption = "Cookies disabled";
+ protected String cookiesDisabledMessage = "This application requires cookies to function.<br/>Please enable cookies in your browser and <u>click here</u> to try again.";
+
/**
* Use {@link CustomizedSystemMessages} to customize
*/
@@ -1462,6 +1474,52 @@ public abstract class Application implements URIHandler,
return (outOfSyncNotificationEnabled ? outOfSyncMessage : null);
}
+ /**
+ * Returns the URL the user should be redirected to after dismissing the
+ * "you have to enable your cookies" message. Typically null.
+ *
+ * @return A URL the user should be redirected to after dismissing the
+ * message or null to reload the current URL.
+ */
+ public String getCookiesDisabledURL() {
+ return cookiesDisabledURL;
+ }
+
+ /**
+ * Determines if "cookies disabled" messages should be shown to the end
+ * user or not. If the notification is disabled the user will be
+ * immediately redirected to the URL returned by
+ * {@link #getCookiesDisabledURL()}.
+ *
+ * @return true to show "cookies disabled" messages to the end user,
+ * false to redirect to the given URL directly
+ */
+ public boolean isCookiesDisabledNotificationEnabled() {
+ return cookiesDisabledNotificationEnabled;
+ }
+
+ /**
+ * Returns the caption of the message shown to the user when cookies are
+ * disabled in the browser.
+ *
+ * @return The caption of the "cookies disabled" message
+ */
+ public String getCookiesDisabledCaption() {
+ return (cookiesDisabledNotificationEnabled ? cookiesDisabledCaption
+ : null);
+ }
+
+ /**
+ * Returns the message shown to the user when cookies are disabled in
+ * the browser.
+ *
+ * @return The "cookies disabled" message
+ */
+ public String getCookiesDisabledMessage() {
+ return (cookiesDisabledNotificationEnabled ? cookiesDisabledMessage
+ : null);
+ }
+
}
/**
@@ -1688,6 +1746,54 @@ public abstract class Application implements URIHandler,
this.outOfSyncMessage = outOfSyncMessage;
}
+ /**
+ * Sets the URL to redirect to when the browser has cookies disabled.
+ *
+ * @param cookiesDisabledURL
+ * the URL to redirect to, or null to reload the current URL
+ */
+ public void setCookiesDisabledURL(String cookiesDisabledURL) {
+ this.cookiesDisabledURL = cookiesDisabledURL;
+ }
+
+ /**
+ * Enables or disables the notification for "cookies disabled" messages.
+ * If disabled, the URL returned by {@link #getCookiesDisabledURL()} is
+ * loaded directly.
+ *
+ * @param cookiesDisabledNotificationEnabled
+ * true to enable "cookies disabled" messages, false
+ * otherwise
+ */
+ public void setCookiesDisabledNotificationEnabled(
+ boolean cookiesDisabledNotificationEnabled) {
+ this.cookiesDisabledNotificationEnabled = cookiesDisabledNotificationEnabled;
+ }
+
+ /**
+ * Sets the caption of the "cookies disabled" notification. Set to null
+ * for no caption. If both caption and message is null, the notification
+ * is disabled.
+ *
+ * @param cookiesDisabledCaption
+ * the caption for the "cookies disabled" notification
+ */
+ public void setCookiesDisabledCaption(String cookiesDisabledCaption) {
+ this.cookiesDisabledCaption = cookiesDisabledCaption;
+ }
+
+ /**
+ * Sets the message of the "cookies disabled" notification. Set to null
+ * for no message. If both caption and message is null, the notification
+ * is disabled.
+ *
+ * @param cookiesDisabledMessage
+ * the message for the "cookies disabled" notification
+ */
+ public void setCookiesDisabledMessage(String cookiesDisabledMessage) {
+ this.cookiesDisabledMessage = cookiesDisabledMessage;
+ }
+
}
/**
diff --git a/src/com/vaadin/data/Container.java b/src/com/vaadin/data/Container.java
index 5777bf2b05..6dbcfe779f 100644
--- a/src/com/vaadin/data/Container.java
+++ b/src/com/vaadin/data/Container.java
@@ -562,26 +562,34 @@ public interface Container extends Serializable {
}
/**
- * Interface is implemented by containers that allow reducing their visible
- * contents with set of filters.
- *
+ * Interface that is implemented by containers which allow reducing their
+ * visible contents based on a set of filters.
+ * <p>
* When a set of filters are set, only items that match the filters are
* included in the visible contents of the container. Still new items that
* do not match filters can be added to the container. Multiple filters can
* be added and the container remembers the state of the filters. When
* multiple filters are added, all filters must match for an item to be
* visible in the container.
- *
+ * </p>
+ * <p>
* When an {@link com.vaadin.data.Ordered} or
* {@link com.vaadin.data.Indexed} container is filtered, all operations of
* these interfaces should only use the filtered contents and the filtered
* indices to the container.
- *
+ * </p>
+ * <p>
+ * How filtering is performed when a {@link Hierarchical} container
+ * implements {@link Filterable} is implementation specific and should be
+ * documented in the implementing class.
+ * </p>
+ * <p>
* Adding items (if supported) to a filtered {@link com.vaadin.data.Ordered}
* or {@link com.vaadin.data.Indexed} container should insert them
* immediately after the indicated visible item. The unfiltered position of
* items added at index 0, at index {@link com.vaadin.data.Container#size()}
* or at an undefined position is up to the implementation.
+ * </p>
*
* @since 5.0
*/
diff --git a/src/com/vaadin/data/util/BeanItemContainer.java b/src/com/vaadin/data/util/BeanItemContainer.java
index 7848de5eed..6510229d5a 100644
--- a/src/com/vaadin/data/util/BeanItemContainer.java
+++ b/src/com/vaadin/data/util/BeanItemContainer.java
@@ -38,9 +38,23 @@ import com.vaadin.data.Property.ValueChangeNotifier;
@SuppressWarnings("serial")
public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
ItemSetChangeNotifier, ValueChangeListener {
- // filtered and unfiltered item IDs
- private ArrayList<BT> list = new ArrayList<BT>();
- private ArrayList<BT> allItems = new ArrayList<BT>();
+ /**
+ * The filteredItems variable contains the items that are visible outside
+ * the container. If filters are enabled this contains a subset of allItems,
+ * if no filters are set this contains the same items as allItems.
+ */
+ private ListSet<BT> filteredItems = new ListSet<BT>();
+
+ /**
+ * The allItems variable always contains all the items in the container.
+ * Some or all of these are also in the filteredItems list.
+ */
+ private ListSet<BT> allItems = new ListSet<BT>();
+
+ /**
+ * Maps all pojos (item ids) in the container (including filtered) to their
+ * corresponding BeanItem.
+ */
private final Map<BT, BeanItem<BT>> beanToItem = new HashMap<BT, BeanItem<BT>>();
// internal data model to obtain property IDs etc.
@@ -89,6 +103,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
* @throws IllegalArgumentException
* If the collection is null or empty.
*/
+ @SuppressWarnings("unchecked")
public BeanItemContainer(Collection<BT> collection)
throws IllegalArgumentException {
if (collection == null || collection.isEmpty()) {
@@ -98,10 +113,22 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
type = (Class<? extends BT>) collection.iterator().next().getClass();
model = BeanItem.getPropertyDescriptors(type);
- int i = 0;
- for (BT bt : collection) {
- addItemAt(i++, bt);
+ addAll(collection);
+ }
+
+ private void addAll(Collection<BT> collection) {
+ // Pre-allocate space for the collection
+ allItems.ensureCapacity(allItems.size() + collection.size());
+
+ int idx = size();
+ for (BT bean : collection) {
+ if (internalAddAt(idx, bean) != null) {
+ idx++;
+ }
}
+
+ // Filter the contents when all items have been added
+ filterAll();
}
/**
@@ -147,36 +174,65 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
* @return Returns new item or null if the operation fails.
*/
private BeanItem<BT> addItemAtInternalIndex(int index, Object newItemId) {
- // Make sure that the Item has not been created yet
- if (allItems.contains(newItemId)) {
+ BeanItem<BT> beanItem = internalAddAt(index, (BT) newItemId);
+ if (beanItem != null) {
+ filterAll();
+ }
+
+ return beanItem;
+ }
+
+ /**
+ * Adds the bean to all internal data structures at the given position.
+ * Fails if the bean is already in the container or is not assignable to the
+ * correct type. Returns the new BeanItem if the bean was added
+ * successfully.
+ *
+ * <p>
+ * Caller should call {@link #filterAll()} after calling this method to
+ * ensure the filtered list is updated.
+ * </p>
+ *
+ * @param position
+ * The position at which the bean should be inserted
+ * @param bean
+ * The bean to insert
+ *
+ * @return true if the bean was added successfully, false otherwise
+ */
+ private BeanItem<BT> internalAddAt(int position, BT bean) {
+ // Make sure that the item has not been added previously
+ if (allItems.contains(bean)) {
return null;
}
- if (type.isAssignableFrom(newItemId.getClass())) {
- BT pojo = (BT) newItemId;
- // "list" will be updated in filterAll()
- allItems.add(index, pojo);
- BeanItem<BT> beanItem = new BeanItem<BT>(pojo, model);
- beanToItem.put(pojo, beanItem);
- // add listeners to be able to update filtering on property changes
- for (Filter filter : filters) {
- // addValueChangeListener avoids adding duplicates
- addValueChangeListener(beanItem, filter.propertyId);
- }
- // it is somewhat suboptimal to filter all items
- filterAll();
- return beanItem;
- } else {
+ if (!type.isAssignableFrom(bean.getClass())) {
return null;
}
+
+ // "filteredList" will be updated in filterAll() which should be invoked
+ // by the caller after calling this method.
+ allItems.add(position, bean);
+ BeanItem<BT> beanItem = new BeanItem<BT>(bean, model);
+ beanToItem.put(bean, beanItem);
+
+ // add listeners to be able to update filtering on property
+ // changes
+ for (Filter filter : filters) {
+ // addValueChangeListener avoids adding duplicates
+ addValueChangeListener(beanItem, filter.propertyId);
+ }
+
+ return beanItem;
}
+ @SuppressWarnings("unchecked")
public BT getIdByIndex(int index) {
- return list.get(index);
+ return filteredItems.get(index);
}
public int indexOfId(Object itemId) {
- return list.indexOf(itemId);
+ return filteredItems.indexOf(itemId);
}
/**
@@ -296,7 +352,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
public boolean containsId(Object itemId) {
// only look at visible items after filtering
- return list.contains(itemId);
+ return filteredItems.contains(itemId);
}
public Property getContainerProperty(Object itemId, Object propertyId) {
@@ -311,8 +367,9 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
return beanToItem.get(itemId);
}
+ @SuppressWarnings("unchecked")
public Collection<BT> getItemIds() {
- return (Collection<BT>) list.clone();
+ return (Collection<BT>) filteredItems.clone();
}
public Class<?> getType(Object propertyId) {
@@ -321,7 +378,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
public boolean removeAllItems() throws UnsupportedOperationException {
allItems.clear();
- list.clear();
+ filteredItems.clear();
// detach listeners from all BeanItems
for (BeanItem<BT> item : beanToItem.values()) {
removeAllValueChangeListeners(item);
@@ -345,7 +402,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
removeAllValueChangeListeners(getItem(itemId));
// remove item
beanToItem.remove(itemId);
- list.remove(itemId);
+ filteredItems.remove(itemId);
fireItemSetChange();
return true;
}
@@ -375,7 +432,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
}
public int size() {
- return list.size();
+ return filteredItems.size();
}
public Collection<Object> getSortableContainerPropertyIds() {
@@ -445,7 +502,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
public void addContainerFilter(Object propertyId, String filterString,
boolean ignoreCase, boolean onlyMatchPrefix) {
if (filters.isEmpty()) {
- list = (ArrayList<BT>) allItems.clone();
+ filteredItems = (ListSet<BT>) allItems.clone();
}
// listen to change events to be able to update filtering
for (BeanItem<BT> item : beanToItem.values()) {
@@ -465,22 +522,22 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
*/
protected void filterAll() {
// avoid notification if the filtering had no effect
- List<BT> originalItems = list;
+ List<BT> originalItems = filteredItems;
// it is somewhat inefficient to do a (shallow) clone() every time
- list = (ArrayList<BT>) allItems.clone();
+ filteredItems = (ListSet<BT>) allItems.clone();
for (Filter f : filters) {
filter(f);
}
// check if exactly the same items are there after filtering to avoid
// unnecessary notifications
// this may be slow in some cases as it uses BT.equals()
- if (!originalItems.equals(list)) {
+ if (!originalItems.equals(filteredItems)) {
fireItemSetChange();
}
}
protected void filter(Filter f) {
- Iterator<BT> iterator = list.iterator();
+ Iterator<BT> iterator = filteredItems.iterator();
while (iterator.hasNext()) {
BT bean = iterator.next();
if (!f.passesFilter(getItem(bean))) {
diff --git a/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java b/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java
index 80065f9254..8b6fedb8e4 100644
--- a/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java
+++ b/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java
@@ -220,7 +220,12 @@ public class ContainerHierarchicalWrapper implements Container.Hierarchical,
return ((Container.Hierarchical) container)
.areChildrenAllowed(itemId);
}
- return !noChildrenAllowed.contains(itemId);
+
+ if (noChildrenAllowed.contains(itemId)) {
+ return false;
+ }
+
+ return containsId(itemId);
}
/*
@@ -284,7 +289,11 @@ public class ContainerHierarchicalWrapper implements Container.Hierarchical,
return ((Container.Hierarchical) container).isRoot(itemId);
}
- return parent.get(itemId) == null;
+ if (parent.containsKey(itemId)) {
+ return false;
+ }
+
+ return containsId(itemId);
}
/*
diff --git a/src/com/vaadin/data/util/HierarchicalContainer.java b/src/com/vaadin/data/util/HierarchicalContainer.java
index 2b5519e651..a404d83eb1 100644
--- a/src/com/vaadin/data/util/HierarchicalContainer.java
+++ b/src/com/vaadin/data/util/HierarchicalContainer.java
@@ -42,16 +42,29 @@ public class HierarchicalContainer extends IndexedContainer implements
private final HashMap<Object, LinkedList<Object>> children = new HashMap<Object, LinkedList<Object>>();
/**
+ * Mapping from Item ID to a list of child IDs when filtered
+ */
+ private HashMap<Object, LinkedList<Object>> filteredChildren = null;
+
+ /**
* List that contains all root elements of the container.
*/
private final LinkedList<Object> roots = new LinkedList<Object>();
+ /**
+ * List that contains all filtered root elements of the container.
+ */
+ private LinkedList<Object> filteredRoots = null;
+
/*
* Can the specified Item have any children? Don't add a JavaDoc comment
* here, we use the default documentation from implemented interface.
*/
public boolean areChildrenAllowed(Object itemId) {
- return !noChildrenAllowed.contains(itemId);
+ if (noChildrenAllowed.contains(itemId)) {
+ return false;
+ }
+ return containsId(itemId);
}
/*
@@ -60,7 +73,14 @@ public class HierarchicalContainer extends IndexedContainer implements
* interface.
*/
public Collection getChildren(Object itemId) {
- final Collection c = children.get(itemId);
+ LinkedList<Object> c;
+
+ if (filteredChildren != null) {
+ c = filteredChildren.get(itemId);
+ } else {
+ c = children.get(itemId);
+ }
+
if (c == null) {
return null;
}
@@ -82,7 +102,11 @@ public class HierarchicalContainer extends IndexedContainer implements
* interface.
*/
public boolean hasChildren(Object itemId) {
- return children.get(itemId) != null;
+ if (filteredChildren != null) {
+ return filteredChildren.containsKey(itemId);
+ } else {
+ return children.containsKey(itemId);
+ }
}
/*
@@ -91,7 +115,15 @@ public class HierarchicalContainer extends IndexedContainer implements
* interface.
*/
public boolean isRoot(Object itemId) {
- return parent.get(itemId) == null;
+ if (filteredRoots != null && !filteredRoots.contains(itemId)) {
+ return false;
+ }
+
+ if (parent.containsKey(itemId)) {
+ return false;
+ }
+
+ return containsId(itemId);
}
/*
@@ -100,7 +132,11 @@ public class HierarchicalContainer extends IndexedContainer implements
* interface.
*/
public Collection rootItemIds() {
- return Collections.unmodifiableCollection(roots);
+ if (filteredRoots != null) {
+ return Collections.unmodifiableCollection(filteredRoots);
+ } else {
+ return Collections.unmodifiableCollection(roots);
+ }
}
/**
@@ -139,25 +175,6 @@ public class HierarchicalContainer extends IndexedContainer implements
return true;
}
- @Override
- public Item addItemAt(int index, Object newItemId) {
- Item retval = super.addItemAt(index, newItemId);
- if (getParent(newItemId) == null) {
- int refIndex = roots.size() - 1;
- int indexOfId = indexOfId(roots.get(refIndex));
- while (indexOfId > index) {
- refIndex--;
- if (refIndex < 0) {
- // inserts as first
- break;
- }
- indexOfId = indexOfId(roots.get(refIndex));
- }
- roots.add(refIndex + 1, newItemId);
- }
- return retval;
- }
-
/**
* <p>
* Sets the parent of an Item. The new parent item must exist and be able to
@@ -191,27 +208,58 @@ public class HierarchicalContainer extends IndexedContainer implements
return true;
}
- // Making root
+ // Making root?
if (newParentId == null) {
+ // The itemId should become a root so we need to
+ // - Remove it from the old parent's children list (also filtered
+ // list)
+ // - Add it as a root
+ // - Remove it from the item -> parent list (parent is null for
+ // roots)
// Removes from old parents children list
- final LinkedList l = children.get(itemId);
+ final LinkedList<Object> l = children.get(itemId);
if (l != null) {
l.remove(itemId);
if (l.isEmpty()) {
children.remove(itemId);
}
+
+ if (filteredChildren != null) {
+ LinkedList<Object> f = filteredChildren.get(itemId);
+ if (f != null) {
+ f.remove(itemId);
+ if (f.isEmpty()) {
+ filteredChildren.remove(f);
+ }
+ }
+ }
}
// Add to be a root
roots.add(itemId);
+ if (filteredRoots != null) {
+ if (passesFilters(itemId)) {
+ filteredRoots.add(itemId);
+ }
+ }
// Updates parent
parent.remove(itemId);
+ fireContentsChange(-1);
+
return true;
}
+ // We get here when the item should not become a root and we need to
+ // - Verify the new parent exists and can have children
+ // - Check that the new parent is not a child of the selected itemId
+ // - Updated the item -> parent mapping to point to the new parent
+ // - Remove the item from the roots list if it was a root
+ // - Remove the item from the old parent's children list if it was not a
+ // root
+
// Checks that the new parent exists in container and can have
// children
if (!containsId(newParentId) || noChildrenAllowed.contains(newParentId)) {
@@ -229,29 +277,92 @@ public class HierarchicalContainer extends IndexedContainer implements
// Updates parent
parent.put(itemId, newParentId);
- LinkedList pcl = children.get(newParentId);
+ LinkedList<Object> pcl = children.get(newParentId);
if (pcl == null) {
- pcl = new LinkedList();
+ // Create an empty list for holding children if one were not
+ // previously created
+ pcl = new LinkedList<Object>();
children.put(newParentId, pcl);
}
pcl.add(itemId);
+ // Add children list for filtered case also
+ if (filteredChildren != null) {
+ LinkedList<Object> f = filteredChildren.get(newParentId);
+ if (f == null) {
+ // Create an empty list for holding children if one were not
+ // previously created
+ f = new LinkedList<Object>();
+ filteredChildren.put(newParentId, f);
+ }
+ }
+
// Removes from old parent or root
if (oldParentId == null) {
roots.remove(itemId);
} else {
- final LinkedList l = children.get(oldParentId);
+ final LinkedList<Object> l = children.get(oldParentId);
if (l != null) {
l.remove(itemId);
if (l.isEmpty()) {
children.remove(oldParentId);
}
}
+ if (filteredChildren != null) {
+ LinkedList<Object> f = filteredChildren.get(oldParentId);
+ if (f != null) {
+ f.remove(itemId);
+ if (f.isEmpty()) {
+ filteredChildren.remove(oldParentId);
+ }
+ }
+ }
}
+ fireContentsChange(-1);
+
return true;
}
+ /**
+ * TODO javadoc
+ *
+ * @param itemId
+ * @param siblingId
+ */
+ public void moveAfterSibling(Object itemId, Object siblingId) {
+ Object parent2 = getParent(itemId);
+ LinkedList<Object> childrenList;
+ if (parent2 == null) {
+ childrenList = roots;
+ } else {
+ childrenList = children.get(parent2);
+ }
+ if (siblingId == null) {
+ childrenList.remove(itemId);
+ childrenList.addFirst(itemId);
+
+ } else {
+ int oldIndex = childrenList.indexOf(itemId);
+ int indexOfSibling = childrenList.indexOf(siblingId);
+ if (indexOfSibling != -1 && oldIndex != -1) {
+ int newIndex;
+ if (oldIndex > indexOfSibling) {
+ newIndex = indexOfSibling + 1;
+ } else {
+ newIndex = indexOfSibling;
+ }
+ childrenList.remove(oldIndex);
+ childrenList.add(newIndex, itemId);
+ } else {
+ throw new IllegalArgumentException(
+ "Given identifiers no not have the same parent.");
+ }
+ }
+ fireContentsChange(-1);
+
+ }
+
/*
* (non-Javadoc)
*
@@ -259,12 +370,21 @@ public class HierarchicalContainer extends IndexedContainer implements
*/
@Override
public Object addItem() {
- final Object id = super.addItem();
- if (id != null && !roots.contains(id)) {
- roots.add(id);
+ final Object itemId = super.addItem();
+ if (itemId == null) {
+ return null;
}
- return id;
+ if (!roots.contains(itemId)) {
+ roots.add(itemId);
+ if (filteredRoots != null) {
+ if (passesFilters(itemId)) {
+ filteredRoots.add(itemId);
+ }
+ }
+ }
+
+ return itemId;
}
/*
@@ -275,9 +395,18 @@ public class HierarchicalContainer extends IndexedContainer implements
@Override
public Item addItem(Object itemId) {
final Item item = super.addItem(itemId);
- if (item != null) {
- roots.add(itemId);
+ if (item == null) {
+ return null;
+ }
+
+ roots.add(itemId);
+
+ if (filteredRoots != null) {
+ if (passesFilters(itemId)) {
+ filteredRoots.add(itemId);
+ }
}
+
return item;
}
@@ -295,6 +424,12 @@ public class HierarchicalContainer extends IndexedContainer implements
parent.clear();
children.clear();
noChildrenAllowed.clear();
+ if (filteredRoots != null) {
+ filteredRoots = null;
+ }
+ if (filteredChildren != null) {
+ filteredChildren = null;
+ }
}
return success;
}
@@ -309,20 +444,44 @@ public class HierarchicalContainer extends IndexedContainer implements
final boolean success = super.removeItem(itemId);
if (success) {
- if (isRoot(itemId)) {
- roots.remove(itemId);
+ // Remove from roots if this was a root
+ if (roots.remove(itemId)) {
+
+ // If filtering is enabled we might need to remove it from the
+ // filtered list also
+ if (filteredRoots != null) {
+ filteredRoots.remove(itemId);
+ }
}
- LinkedList<Object> remove = children.remove(itemId);
- if (remove != null) {
- for (Object object : remove) {
- removeItem(object);
+
+ // Clear the children list. Old children will now become root nodes
+ LinkedList<Object> childNodeIds = children.remove(itemId);
+ if (childNodeIds != null) {
+ if (filteredChildren != null) {
+ filteredChildren.remove(itemId);
+ }
+ for (Object childId : childNodeIds) {
+ setParent(childId, null);
}
}
- final Object p = parent.get(itemId);
- if (p != null) {
- final LinkedList c = children.get(p);
+
+ // Parent of the item that we are removing will contain the item id
+ // in its children list
+ final Object parentItemId = parent.get(itemId);
+ if (parentItemId != null) {
+ final LinkedList<Object> c = children.get(parentItemId);
if (c != null) {
c.remove(itemId);
+
+ // Found in the children list so might also be in the
+ // filteredChildren list
+ if (filteredChildren != null) {
+ LinkedList<Object> f = filteredChildren
+ .get(parentItemId);
+ if (f != null) {
+ f.remove(parentItemId);
+ }
+ }
}
}
parent.remove(itemId);
@@ -332,6 +491,35 @@ public class HierarchicalContainer extends IndexedContainer implements
return success;
}
+ /**
+ * Removes the Item identified by ItemId from the Container and all its
+ * children.
+ *
+ * @see #removeItem(Object)
+ * @param itemId
+ * the identifier of the Item to remove
+ * @return true if the operation succeeded
+ */
+ public boolean removeItemRecursively(Object itemId) {
+ boolean success = true;
+ Collection<Object> children2 = getChildren(itemId);
+ if (children2 != null) {
+ Object[] array = children2.toArray();
+ for (int i = 0; i < array.length; i++) {
+ boolean removeItemRecursively = removeItemRecursively(array[i]);
+ if (!removeItemRecursively) {
+ success = false;
+ }
+ }
+ }
+ boolean removeItem = removeItem(itemId);
+ if (!removeItem) {
+ success = false;
+ }
+ return success;
+
+ }
+
/*
* (non-Javadoc)
*
@@ -347,4 +535,40 @@ public class HierarchicalContainer extends IndexedContainer implements
}
}
+ /*
+ * Overridden to provide filtering for root & children items.
+ *
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.IndexedContainer#updateContainerFiltering()
+ */
+ @Override
+ protected void updateContainerFiltering() {
+ super.updateContainerFiltering();
+
+ filteredRoots = new LinkedList<Object>();
+ filteredChildren = new HashMap<Object, LinkedList<Object>>();
+
+ // Filter root item ids
+ for (Object rootId : roots) {
+ if (passesFilters(rootId)) {
+ filteredRoots.add(rootId);
+ }
+ }
+
+ // Filter children
+ for (Object parent : children.keySet()) {
+ if (passesFilters(parent)) {
+ LinkedList<Object> filtered = new LinkedList<Object>();
+ filteredChildren.put(parent, filtered);
+ for (Object child : children.get(parent)) {
+ if (passesFilters(child)) {
+ filtered.add(child);
+ }
+ }
+ }
+ }
+
+ }
+
}
diff --git a/src/com/vaadin/data/util/IndexedContainer.java b/src/com/vaadin/data/util/IndexedContainer.java
index d6d6d9e77c..3bac19cd7a 100644
--- a/src/com/vaadin/data/util/IndexedContainer.java
+++ b/src/com/vaadin/data/util/IndexedContainer.java
@@ -469,7 +469,13 @@ public class IndexedContainer implements Container.Indexed,
return null;
}
try {
- return itemIds.get(itemIds.indexOf(itemId) + 1);
+ int idx = itemIds.indexOf(itemId);
+ if (idx == -1) {
+ // If the given Item is not found in the Container,
+ // null is returned.
+ return null;
+ }
+ return itemIds.get(idx + 1);
} catch (final IndexOutOfBoundsException e) {
return null;
}
@@ -548,6 +554,11 @@ public class IndexedContainer implements Container.Indexed,
* java.lang.Object)
*/
public Item addItemAfter(Object previousItemId, Object newItemId) {
+ // Adding an item after null item adds the item as first item of the
+ // ordered container.
+ if (previousItemId == null) {
+ return addItemAt(0, newItemId);
+ }
// Get the index of the addition
int index = -1;
@@ -574,7 +585,11 @@ public class IndexedContainer implements Container.Indexed,
// Creates a new id
final Object id = generateId();
- return addItemAfter(previousItemId, id);
+ if (addItemAfter(previousItemId, id) != null) {
+ return id;
+ } else {
+ return null;
+ }
}
/*
@@ -953,7 +968,7 @@ public class IndexedContainer implements Container.Indexed,
* @param addedItemIndex
* index of new item if change event was an item addition
*/
- private void fireContentsChange(int addedItemIndex) {
+ protected void fireContentsChange(int addedItemIndex) {
if (itemSetChangeListeners != null) {
final Object[] l = itemSetChangeListeners.toArray();
final Container.ItemSetChangeEvent event = new IndexedContainer.ItemSetChangeEvent(
@@ -1549,7 +1564,7 @@ public class IndexedContainer implements Container.Indexed,
}
}
- private void updateContainerFiltering() {
+ protected void updateContainerFiltering() {
// Clearing filters?
if (filters == null || filters.isEmpty()) {
@@ -1571,7 +1586,7 @@ public class IndexedContainer implements Container.Indexed,
// Filter
for (final Iterator i = itemIds.iterator(); i.hasNext();) {
final Object id = i.next();
- if (passesFilters(new IndexedContainerItem(id))) {
+ if (passesFilters(id)) {
filteredItemIds.add(id);
}
}
@@ -1579,6 +1594,10 @@ public class IndexedContainer implements Container.Indexed,
fireContentsChange(-1);
}
+ protected final boolean passesFilters(Object itemId) {
+ return passesFilters(new IndexedContainerItem(itemId));
+ }
+
private boolean passesFilters(Item item) {
if (filters == null) {
return true;
diff --git a/src/com/vaadin/data/util/ListSet.java b/src/com/vaadin/data/util/ListSet.java
new file mode 100644
index 0000000000..8dc8c6bbfd
--- /dev/null
+++ b/src/com/vaadin/data/util/ListSet.java
@@ -0,0 +1,198 @@
+package com.vaadin.data.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * ListSet is an internal Vaadin class which implements a combination of a List
+ * and a Set. The main purpose of this class is to provide a fast
+ * {@link #contains(Object)} method. Each inserted object must by unique (as
+ * specified by {@link #equals(Object)}).
+ *
+ * This class is subject to change and should not be used outside Vaadin core.
+ */
+public class ListSet<E> extends ArrayList<E> {
+ private HashSet<E> itemSet = null;
+
+ public ListSet() {
+ super();
+ itemSet = new HashSet<E>();
+ }
+
+ public ListSet(Collection<? extends E> c) {
+ super(c);
+ itemSet = new HashSet<E>(c.size());
+ itemSet.addAll(c);
+ }
+
+ public ListSet(int initialCapacity) {
+ super(initialCapacity);
+ itemSet = new HashSet<E>(initialCapacity);
+ }
+
+ // Delegate contains operations to the set
+ @Override
+ public boolean contains(Object o) {
+ return itemSet.contains(o);
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ return itemSet.containsAll(c);
+ }
+
+ // Methods for updating the set when the list is updated.
+ @Override
+ public boolean add(E e) {
+ if (contains(e)) {
+ // Duplicates are not allowed
+ return false;
+ }
+
+ if (super.add(e)) {
+ itemSet.add(e);
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+ /**
+ * Works as java.util.ArrayList#add(int, java.lang.Object) but returns
+ * immediately if the element is already in the ListSet.
+ */
+ @Override
+ public void add(int index, E element) {
+ if (contains(element)) {
+ // Duplicates are not allowed
+ return;
+ }
+
+ super.add(index, element);
+ itemSet.add(element);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends E> c) {
+ boolean modified = false;
+ Iterator<? extends E> i = c.iterator();
+ while (i.hasNext()) {
+ E e = i.next();
+ if (contains(e)) {
+ continue;
+ }
+
+ if (add(e)) {
+ itemSet.add(e);
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends E> c) {
+ ensureCapacity(size() + c.size());
+
+ boolean modified = false;
+ Iterator<? extends E> i = c.iterator();
+ while (i.hasNext()) {
+ E e = i.next();
+ if (contains(e)) {
+ continue;
+ }
+
+ add(index++, e);
+ itemSet.add(e);
+ modified = true;
+ }
+
+ return modified;
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ itemSet.clear();
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ if (!contains(o)) {
+ return -1;
+ }
+
+ return super.indexOf(o);
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ if (!contains(o)) {
+ return -1;
+ }
+
+ return super.lastIndexOf(o);
+ }
+
+ @Override
+ public E remove(int index) {
+ E e = super.remove(index);
+
+ if (e != null) {
+ itemSet.remove(e);
+ }
+
+ return e;
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ if (super.remove(o)) {
+ itemSet.remove(o);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected void removeRange(int fromIndex, int toIndex) {
+ HashSet<E> toRemove = new HashSet<E>();
+ for (int idx = fromIndex; idx < toIndex; idx++) {
+ toRemove.add(get(idx));
+ }
+ super.removeRange(fromIndex, toIndex);
+ itemSet.removeAll(toRemove);
+ }
+
+ @Override
+ public E set(int index, E element) {
+ if (contains(element)) {
+ // Element already exist in the list
+ if (get(index) == element) {
+ // At the same position, nothing to be done
+ return element;
+ } else {
+ // At another position, cannot set
+ return null;
+ }
+ }
+
+ E old = super.set(index, element);
+ itemSet.remove(old);
+ itemSet.add(element);
+
+ return old;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object clone() {
+ ListSet<E> v = (ListSet<E>) super.clone();
+ v.itemSet = new HashSet<E>(itemSet);
+ return v;
+ }
+
+}
diff --git a/src/com/vaadin/terminal/FileResource.java b/src/com/vaadin/terminal/FileResource.java
index 46f1a6c028..571622b0e4 100644
--- a/src/com/vaadin/terminal/FileResource.java
+++ b/src/com/vaadin/terminal/FileResource.java
@@ -10,6 +10,7 @@ import java.io.FileNotFoundException;
import com.vaadin.Application;
import com.vaadin.service.FileTypeResolver;
+import com.vaadin.terminal.Terminal.ErrorEvent;
/**
* <code>FileResources</code> are files or directories on local filesystem. The
@@ -67,7 +68,15 @@ public class FileResource implements ApplicationResource {
ds.setCacheTime(cacheTime);
return ds;
} catch (final FileNotFoundException e) {
- // No logging for non-existing files at this level.
+ // Log the exception using the application error handler
+ getApplication().getErrorHandler().terminalError(new ErrorEvent() {
+
+ public Throwable getThrowable() {
+ return e;
+ }
+
+ });
+
return null;
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
index 39f4e845f7..5bcf613f6d 100644
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
@@ -148,20 +148,15 @@ public class ApplicationConfiguration {
int lastdot = module.lastIndexOf(".");
String base = module.substring(0, lastdot);
String simpleName = module.substring(lastdot + 1);
- // if (!wsname.startsWith(base) || !wsname.endsWith(simpleName)) {
- // // WidgetSet module name does not match implementation name;
- // // probably inherited WidgetSet with entry-point. Skip.
- // GWT.log("Ignored init for " + wsname + " when starting " + module,
- // null);
- // return;
- // }
if (initedWidgetSet != null) {
- // Something went wrong: multiple widgetsets inited
- String msg = "Tried to init " + widgetset.getClass().getName()
- + ", but " + initedWidgetSet.getClass().getName()
- + " was already inited.";
- ApplicationConnection.getConsole().log(msg);
+ // Multiple widgetsets inited; can happen with custom WS + entry
+ // point
+ String msg = "Ignoring " + widgetset.getClass().getName()
+ + ", because " + initedWidgetSet.getClass().getName()
+ + " was already inited (if this is wrong, your entry point"
+ + " is probably not first your .gwt.xml).";
+ throw new IllegalStateException(msg);
}
initedWidgetSet = widgetset;
ArrayList<String> appIds = new ArrayList<String>();
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
index 34e3580608..8574bc0476 100755
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
@@ -1116,7 +1116,7 @@ public class ApplicationConnection {
* @param newValue
* the new value to be sent
* @param immediate
- * true if the update is to be sent as suun as possible
+ * true if the update is to be sent as soon as possible
*/
public void updateVariable(String paintableId, String variableName,
Paintable newValue, boolean immediate) {
@@ -1139,7 +1139,7 @@ public class ApplicationConnection {
* @param newValue
* the new value to be sent
* @param immediate
- * true if the update is to be sent as suun as possible
+ * true if the update is to be sent as soon as possible
*/
public void updateVariable(String paintableId, String variableName,
@@ -1162,7 +1162,7 @@ public class ApplicationConnection {
* @param newValue
* the new value to be sent
* @param immediate
- * true if the update is to be sent as suun as possible
+ * true if the update is to be sent as soon as possible
*/
public void updateVariable(String paintableId, String variableName,
@@ -1186,7 +1186,7 @@ public class ApplicationConnection {
* @param newValue
* the new value to be sent
* @param immediate
- * true if the update is to be sent as suun as possible
+ * true if the update is to be sent as soon as possible
*/
public void updateVariable(String paintableId, String variableName,
@@ -1210,7 +1210,7 @@ public class ApplicationConnection {
* @param newValue
* the new value to be sent
* @param immediate
- * true if the update is to be sent as suun as possible
+ * true if the update is to be sent as soon as possible
*/
public void updateVariable(String paintableId, String variableName,
@@ -1234,7 +1234,7 @@ public class ApplicationConnection {
* @param newValue
* the new value to be sent
* @param immediate
- * true if the update is to be sent as suun as possible
+ * true if the update is to be sent as soon as possible
*/
public void updateVariable(String paintableId, String variableName,
@@ -1258,7 +1258,7 @@ public class ApplicationConnection {
* @param newValue
* the new value to be sent
* @param immediate
- * true if the update is to be sent as suun as possible
+ * true if the update is to be sent as soon as possible
*/
public void updateVariable(String paintableId, String variableName,
@@ -1282,7 +1282,7 @@ public class ApplicationConnection {
* @param newValue
* the new value to be sent
* @param immediate
- * true if the update is to be sent as suun as possible
+ * true if the update is to be sent as soon as possible
*/
public void updateVariable(String paintableId, String variableName,
Map<String, Object> map, boolean immediate) {
@@ -1347,7 +1347,7 @@ public class ApplicationConnection {
* @param newValue
* the new value to be sent
* @param immediate
- * true if the update is to be sent as suun as possible
+ * true if the update is to be sent as soon as possible
*/
public void updateVariable(String paintableId, String variableName,
String[] values, boolean immediate) {
@@ -1382,7 +1382,7 @@ public class ApplicationConnection {
* @param newValue
* the new value to be sent
* @param immediate
- * true if the update is to be sent as suun as possible
+ * true if the update is to be sent as soon as possible
*/
public void updateVariable(String paintableId, String variableName,
Object[] values, boolean immediate) {
diff --git a/src/com/vaadin/terminal/gwt/client/ClientExceptionHandler.java b/src/com/vaadin/terminal/gwt/client/ClientExceptionHandler.java
index 724bd24a69..f1b01509d4 100644
--- a/src/com/vaadin/terminal/gwt/client/ClientExceptionHandler.java
+++ b/src/com/vaadin/terminal/gwt/client/ClientExceptionHandler.java
@@ -3,7 +3,7 @@ package com.vaadin.terminal.gwt.client;
public class ClientExceptionHandler {
public static void displayError(Throwable e) {
- displayError(e.getMessage());
+ displayError(e.getClass().getName() + ": " + e.getMessage());
e.printStackTrace();
}
diff --git a/src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java b/src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java
index 8ee6b0bb14..c34e5d8bb3 100644
--- a/src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java
+++ b/src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java
@@ -38,7 +38,14 @@ public class DefaultWidgetSet implements WidgetSet {
* This is the entry point method. It will start the first
*/
public void onModuleLoad() {
- ApplicationConfiguration.initConfigurations(this);
+ try {
+ ApplicationConfiguration.initConfigurations(this);
+ } catch (Exception e) {
+ // Log & don't continue;
+ // custom WidgetSets w/ entry points will cause this
+ ApplicationConnection.getConsole().log(e.getMessage());
+ return;
+ }
ApplicationConfiguration.startNextApplication(); // start first app
map = GWT.create(WidgetMap.class);
}
diff --git a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java
index 45b8c9353b..172e4df627 100755
--- a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java
+++ b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java
@@ -8,6 +8,7 @@ import java.util.List;
import java.util.Set;
import com.google.gwt.core.client.JsArray;
+import com.google.gwt.dom.client.Style.FontWeight;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM;
@@ -304,6 +305,10 @@ public final class VDebugConsole extends VOverlay implements Console {
* @see com.vaadin.terminal.gwt.client.Console#log(java.lang.String)
*/
public void log(String msg) {
+ if (msg == null) {
+ msg = "null";
+ }
+
panel.add(new HTML(msg));
System.out.println(msg);
consoleLog(msg);
@@ -315,7 +320,14 @@ public final class VDebugConsole extends VOverlay implements Console {
* @see com.vaadin.terminal.gwt.client.Console#error(java.lang.String)
*/
public void error(String msg) {
- panel.add((new HTML(msg)));
+ if (msg == null) {
+ msg = "null";
+ }
+
+ HTML html = new HTML(msg);
+ html.getElement().getStyle().setColor("#f00");
+ html.getElement().getStyle().setFontWeight(FontWeight.BOLD);
+ panel.add(html);
System.err.println(msg);
consoleErr(msg);
}
@@ -327,7 +339,13 @@ public final class VDebugConsole extends VOverlay implements Console {
* Object)
*/
public void printObject(Object msg) {
- panel.add((new Label(msg.toString())));
+ String str;
+ if (msg == null) {
+ str = "null";
+ } else {
+ str = msg.toString();
+ }
+ panel.add((new Label(str)));
consoleLog(msg.toString());
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java
index bf13530d7f..90cf102cb9 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java
@@ -184,10 +184,11 @@ public class VCssLayout extends SimplePanel implements Paintable, Container {
// loop oldWidgetWrappers that where not re-attached and unregister
// them
- for (final Iterator<Widget> it = oldWidgets.iterator(); it
- .hasNext();) {
- final Paintable w = (Paintable) it.next();
- client.unregisterPaintable(w);
+ for (Widget w : oldWidgets) {
+ if (w instanceof Paintable) {
+ final Paintable p = (Paintable) w;
+ client.unregisterPaintable(p);
+ }
widgetToCaption.remove(w);
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java b/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java
index 7d69e5682a..ffd09dab2c 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java
@@ -140,6 +140,7 @@ public class VEmbedded extends HTML implements Paintable {
parameters.put("movie", getSrc(uidl, client));
}
+ // Add the parameters to the Object
for (String name : parameters.keySet()) {
html += "<param name=\"" + escapeAttribute(name)
+ "\" value=\""
@@ -147,9 +148,15 @@ public class VEmbedded extends HTML implements Paintable {
}
html += "<embed src=\"" + getSrc(uidl, client) + "\" width=\""
- + width + "\" height=\"" + height + "\"></embed>";
+ + width + "\" height=\"" + height + "\" ";
- html += "</object>";
+ // Add the parameters to the Embed
+ for (String name : parameters.keySet()) {
+ html += escapeAttribute(name) + "=\""
+ + escapeAttribute(parameters.get(name)) + "\" ";
+ }
+
+ html += "></embed></object>";
setHTML(html);
} else if (mime.equals("image/svg+xml")) {
String data;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java
index 2dcf7562ae..669b5b90ea 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java
@@ -631,6 +631,23 @@ public class VFilterSelect extends Composite implements Paintable, Field,
public void onLoad(LoadEvent event) {
updateRootWidth();
updateSelectedIconPosition();
+
+ /*
+ * We need to re-calculate the widths in IE at load time to
+ * ensure that the text is not placed behind the icon. #3991
+ */
+ if (BrowserInfo.get().isIE()) {
+ int tbWidth = Util.getRequiredWidth(tb);
+ int openerWidth = Util.getRequiredWidth(popupOpener);
+ int iconWidth = selectedItemIcon.isAttached() ? Util
+ .measureMarginLeft(tb.getElement())
+ - Util.measureMarginLeft(selectedItemIcon
+ .getElement()) : 0;
+
+ int w = tbWidth + openerWidth + iconWidth;
+ tb.setWidth((tbWidth - getTextboxPadding()) + "px");
+ setTextboxWidth(w);
+ }
}
});
@@ -883,8 +900,8 @@ public class VFilterSelect extends Composite implements Paintable, Field,
panel.remove(selectedItemIcon);
updateRootWidth();
} else {
- selectedItemIcon.setUrl(iconUri);
panel.insert(selectedItemIcon, 0);
+ selectedItemIcon.setUrl(iconUri);
updateRootWidth();
updateSelectedIconPosition();
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java b/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
index 0a28fd6b41..75ecbd3249 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
@@ -8,11 +8,14 @@ import java.util.Stack;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.HasHTML;
import com.google.gwt.user.client.ui.PopupPanel;
@@ -27,7 +30,8 @@ import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
public class VMenuBar extends Widget implements Paintable,
- CloseHandler<PopupPanel>, ContainerResizedListener {
+CloseHandler<PopupPanel>, ContainerResizedListener,
+ValueChangeHandler<String> {
/** Set the CSS class name to allow styling. */
public static final String CLASSNAME = "v-menubar";
@@ -76,6 +80,8 @@ public class VMenuBar extends Widget implements Paintable,
if (!subMenu) {
setStylePrimaryName(CLASSNAME);
+ // Monitor back&forward buttons
+ History.addValueChangeHandler(this);
} else {
setStylePrimaryName(CLASSNAME + "-submenu");
}
@@ -866,4 +872,12 @@ public class VMenuBar extends Widget implements Paintable,
return w;
}
+ public void onValueChange(ValueChangeEvent<String> arg0) {
+ // Close menu if user uses back & forward buttons #4109
+ if (!subMenu) {
+ setSelected(null);
+ hideChildren();
+ menuVisible = false;
+ }
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java b/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java
index e544e1f9ce..ef7e183698 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java
@@ -19,7 +19,7 @@ import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VTooltip;
-public class VNativeButton extends Button implements Paintable {
+public class VNativeButton extends Button implements Paintable, ClickHandler {
public static final String CLASSNAME = "v-nativebutton";
@@ -48,18 +48,8 @@ public class VNativeButton extends Button implements Paintable {
getElement().appendChild(captionElement);
captionElement.setClassName(getStyleName() + "-caption");
- addClickHandler(new ClickHandler() {
- public void onClick(ClickEvent event) {
- if (id == null || client == null) {
- return;
- }
- if (BrowserInfo.get().isSafari()) {
- VNativeButton.this.setFocus(true);
- }
- client.updateVariable(id, "state", true, true);
- clickPending = false;
- }
- });
+ addClickHandler(this);
+
sinkEvents(VTooltip.TOOLTIP_EVENTS);
sinkEvents(Event.ONMOUSEDOWN);
sinkEvents(Event.ONMOUSEUP);
@@ -179,4 +169,24 @@ public class VNativeButton extends Button implements Paintable {
}
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event
+ * .dom.client.ClickEvent)
+ */
+ public void onClick(ClickEvent event) {
+ if (id == null || client == null) {
+ return;
+ }
+
+ if (BrowserInfo.get().isSafari()) {
+ VNativeButton.this.setFocus(true);
+ }
+
+ client.updateVariable(id, "state", true, true);
+ clickPending = false;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VPanel.java
index f9da8f67d9..d41a739655 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VPanel.java
@@ -189,7 +189,6 @@ public class VPanel extends SimplePanel implements Container {
}
layout.updateFromUIDL(layoutUidl, client);
- runHacks(false);
// We may have actions attached to this panel
if (uidl.getChildCount() > 1) {
final int cnt = uidl.getChildCount();
@@ -224,6 +223,10 @@ public class VPanel extends SimplePanel implements Container {
scrollLeft = contentNode.getScrollLeft();
}
+ // Must be run after scrollTop is set as Webkit overflow fix re-sets the
+ // scrollTop
+ runHacks(false);
+
rendering = false;
}
@@ -393,7 +396,8 @@ public class VPanel extends SimplePanel implements Container {
super.setHeight(height);
if (height != null && height != "") {
final int targetHeight = getOffsetHeight();
- int containerHeight = targetHeight - captionNode.getOffsetHeight()
+ int containerHeight = targetHeight
+ - captionNode.getParentElement().getOffsetHeight()
- bottomDecoration.getOffsetHeight()
- getContainerBorderHeight();
if (containerHeight < 0) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java
index 8d83e8b2b5..9b504bc5f3 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java
@@ -52,7 +52,6 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field,
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
boolean lastReadOnlyState = readonly;
super.updateFromUIDL(uidl, client);
- addStyleName(CLASSNAME + "-popupcalendar");
popup.setStyleName(VDateField.CLASSNAME + "-popup "
+ VDateField.CLASSNAME + "-"
+ resolutionToString(currentResolution));
@@ -67,6 +66,12 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field,
}
+ @Override
+ public void setStyleName(String style) {
+ // make sure the style is there before size calculation
+ super.setStyleName(style + " " + CLASSNAME + "-popupcalendar");
+ }
+
public void onClick(ClickEvent event) {
if (event.getSource() == calendarToggle && !open && !readonly) {
open = true;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
index 59c5d252fe..53f0033bcd 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
@@ -19,11 +19,14 @@ import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.dom.client.TableSectionElement;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FlowPanel;
@@ -72,7 +75,7 @@ import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
* TODO implement unregistering for child components in Cells
*/
public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
- VHasDropHandler {
+ VHasDropHandler, ValueChangeHandler<String> {
public static final String CLASSNAME = "v-table";
public static final String ITEM_CLICK_EVENT_ID = "itemClick";
@@ -168,6 +171,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
rowRequestHandler = new RowRequestHandler();
+ // Handle back & forward browser buttons
+ History.addValueChangeHandler(this);
}
@SuppressWarnings("unchecked")
@@ -3264,4 +3269,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
+ public void onValueChange(ValueChangeEvent<String> arg0) {
+ client.getContextMenu().hide();
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java
index d7a11427fb..101c1e9848 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java
@@ -122,6 +122,9 @@ public class VSplitPanel extends ComplexPanel implements Container,
private boolean rendering = false;
+ /* The current position of the split handle in either percentages or pixels */
+ private String position;
+
public VSplitPanel() {
this(ORIENTATION_HORIZONTAL);
}
@@ -208,7 +211,8 @@ public class VSplitPanel extends ComplexPanel implements Container,
setStylenames();
- setSplitPosition(uidl.getStringAttribute("position"));
+ position = uidl.getStringAttribute("position");
+ setSplitPosition(position);
final Paintable newFirstChild = client.getPaintable(uidl
.getChildUIDL(0));
@@ -257,14 +261,26 @@ public class VSplitPanel extends ComplexPanel implements Container,
}
private void setSplitPosition(String pos) {
+ if (pos == null) {
+ return;
+ }
+
+ // Convert percentage values to pixels
+ if (pos.indexOf("%") > 0) {
+ pos = Float.parseFloat(pos.substring(0, pos.length() - 1))
+ / 100
+ * (orientation == ORIENTATION_HORIZONTAL ? getOffsetWidth()
+ : getOffsetHeight()) + "px";
+ }
+
if (orientation == ORIENTATION_HORIZONTAL) {
DOM.setStyleAttribute(splitter, "left", pos);
} else {
DOM.setStyleAttribute(splitter, "top", pos);
}
+
iLayout();
client.runDescendentsLayout(this);
-
}
/*
@@ -441,9 +457,6 @@ public class VSplitPanel extends ComplexPanel implements Container,
onVerticalMouseMove(y);
break;
}
- iLayout();
- // TODO Check if this is needed
- client.runDescendentsLayout(this);
}
@@ -455,7 +468,18 @@ public class VSplitPanel extends ComplexPanel implements Container,
if (newX + getSplitterSize() > getOffsetWidth()) {
newX = getOffsetWidth() - getSplitterSize();
}
- DOM.setStyleAttribute(splitter, "left", newX + "px");
+
+ if (position.indexOf("%") > 0) {
+ float pos = newX;
+ // 100% needs special handling
+ if (newX + getSplitterSize() >= getOffsetWidth()) {
+ pos = getOffsetWidth();
+ }
+ position = pos / getOffsetWidth() * 100 + "%";
+ }
+
+ setSplitPosition(newX + "px");
+
if (origX != newX) {
resized = true;
}
@@ -470,7 +494,18 @@ public class VSplitPanel extends ComplexPanel implements Container,
if (newY + getSplitterSize() > getOffsetHeight()) {
newY = getOffsetHeight() - getSplitterSize();
}
- DOM.setStyleAttribute(splitter, "top", newY + "px");
+
+ if (position.indexOf("%") > 0) {
+ float pos = newY;
+ // 100% needs special handling
+ if (newY + getSplitterSize() >= getOffsetHeight()) {
+ pos = getOffsetHeight();
+ }
+ position = pos / getOffsetHeight() * 100 + "%";
+ }
+
+ setSplitPosition(newY + "px");
+
if (origY != newY) {
resized = true;
}
@@ -554,9 +589,9 @@ public class VSplitPanel extends ComplexPanel implements Container,
this.height = height;
super.setHeight(height);
+
if (!rendering && client != null) {
- iLayout();
- client.runDescendentsLayout(this);
+ setSplitPosition(position);
}
}
@@ -568,9 +603,9 @@ public class VSplitPanel extends ComplexPanel implements Container,
this.width = width;
super.setWidth(width);
+
if (!rendering && client != null) {
- iLayout();
- client.runDescendentsLayout(this);
+ setSplitPosition(position);
}
}
@@ -627,12 +662,14 @@ public class VSplitPanel extends ComplexPanel implements Container,
* Updates the new split position back to server.
*/
private void updateSplitPositionToServer() {
- // We always send pixel values to server
- final String position = orientation == ORIENTATION_HORIZONTAL ? splitter
- .getStyle().getProperty("left")
- : splitter.getStyle().getProperty("top");
- final int pos = Integer.parseInt(position.substring(0, position
- .length() - 2));
+ int pos = 0;
+ if (position.indexOf("%") > 0) {
+ pos = Float.valueOf(position.substring(0, position.length() - 1))
+ .intValue();
+ } else {
+ pos = Integer
+ .parseInt(position.substring(0, position.length() - 2));
+ }
client.updateVariable(id, "position", pos, immediate);
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java b/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
index fe2c03496c..f4bc96f66a 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
@@ -218,6 +218,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
if (prompting) {
setText("");
removeStyleDependentName(CLASSNAME_PROMPT);
+ setPrompting(false);
if (BrowserInfo.get().isIE6()) {
// IE6 does not show the cursor when tabbing into the field
setCursorPos(0);
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VView.java b/src/com/vaadin/terminal/gwt/client/ui/VView.java
index 838b60a6d8..033d35dab1 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VView.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VView.java
@@ -372,10 +372,6 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
onResize(Window.getClientWidth(), Window.getClientHeight());
- if (BrowserInfo.get().isSafari()) {
- Util.runWebkitOverflowAutoFix(getElement());
- }
-
// finally set scroll position from UIDL
if (uidl.hasVariable("scrollTop")) {
scrollable = true;
@@ -387,6 +383,12 @@ public class VView extends SimplePanel implements Container, ResizeHandler,
scrollable = false;
}
+ // Safari workaround must be run after scrollTop is updated as it sets
+ // scrollTop using a deferred command.
+ if (BrowserInfo.get().isSafari()) {
+ Util.runWebkitOverflowAutoFix(getElement());
+ }
+
rendering = false;
}
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
index 428a9b38b9..148474bccc 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
@@ -14,6 +14,7 @@ import java.security.GeneralSecurityException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
@@ -28,12 +29,10 @@ import javax.portlet.PortalContext;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
-import javax.portlet.PortletMode;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.PortletSession;
import javax.portlet.PortletURL;
-import javax.portlet.RenderMode;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
@@ -47,9 +46,14 @@ import com.vaadin.Application.SystemMessages;
import com.vaadin.external.org.apache.commons.fileupload.portlet.PortletFileUpload;
import com.vaadin.terminal.DownloadStream;
import com.vaadin.terminal.Terminal;
+import com.vaadin.terminal.gwt.client.ApplicationConfiguration;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.ui.Window;
/**
+ * Portlet 2.0 base class. This replaces the servlet in servlet/portlet 1.0
+ * deployments and handles various portlet requests from the browser.
+ *
* TODO Document me!
*
* @author peholmst
@@ -193,7 +197,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
* the Default to be used.
* @return String value or default if not found
*/
- private String getApplicationOrSystemProperty(String parameterName,
+ protected String getApplicationOrSystemProperty(String parameterName,
String defaultValue) {
String val = null;
@@ -240,7 +244,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
}
}
- enum RequestType {
+ protected enum RequestType {
FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APPLICATION_RESOURCE, DUMMY, EVENT, ACTION, UNKNOWN;
}
@@ -304,7 +308,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
RequestType requestType = getRequestType(request);
if (requestType == RequestType.UNKNOWN) {
- System.err.println("Unknown request type");
+ handleUnknownRequest(request, response);
} else if (requestType == RequestType.DUMMY) {
/*
* This dummy page is used by action responses to redirect to, in
@@ -317,8 +321,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(out, "UTF-8")));
outWriter.print("<html><body>dummy page</body></html>");
- outWriter.flush();
- out.close();
+ outWriter.close();
} else if (requestType == RequestType.STATIC_FILE) {
serveStaticResources((ResourceRequest) request,
(ResourceResponse) response);
@@ -386,20 +389,43 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
/* Notify listeners */
+ // Finds the window within the application
+ Window window = null;
+ synchronized (application) {
+ if (application.isRunning()) {
+ switch (requestType) {
+ case FILE_UPLOAD:
+ // no window
+ break;
+ case APPLICATION_RESOURCE:
+ // use main window - should not need any window
+ window = application.getMainWindow();
+ break;
+ default:
+ window = applicationManager.getApplicationWindow(
+ request, this, application, null);
+ }
+ // if window not found, not a problem - use null
+ }
+ }
+
// TODO Should this happen before or after the transaction
// starts?
if (request instanceof RenderRequest) {
applicationContext.firePortletRenderRequest(application,
- (RenderRequest) request, (RenderResponse) response);
+ window, (RenderRequest) request,
+ (RenderResponse) response);
} else if (request instanceof ActionRequest) {
applicationContext.firePortletActionRequest(application,
- (ActionRequest) request, (ActionResponse) response);
+ window, (ActionRequest) request,
+ (ActionResponse) response);
} else if (request instanceof EventRequest) {
applicationContext.firePortletEventRequest(application,
- (EventRequest) request, (EventResponse) response);
+ window, (EventRequest) request,
+ (EventResponse) response);
} else if (request instanceof ResourceRequest) {
applicationContext.firePortletResourceRequest(application,
- (ResourceRequest) request,
+ window, (ResourceRequest) request,
(ResourceResponse) response);
}
@@ -412,7 +438,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
// Handles AJAX UIDL requests
applicationManager.handleUidlRequest(
(ResourceRequest) request,
- (ResourceResponse) response, this);
+ (ResourceResponse) response, this, window);
return;
} else {
/*
@@ -423,45 +449,9 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
return;
}
- /*
- * Always use the main window when running inside a portlet.
- */
- Window window = getPortletWindow(request, application);
- if (window == null) {
- throw new PortletException(ERROR_NO_WINDOW_FOUND);
- }
-
- /*
- * Sets terminal type for the window, if not already set
- */
- if (window.getTerminal() == null) {
- window.setTerminal(applicationContext.getBrowser());
- }
-
- /*
- * Handle parameters
- */
- final Map<String, String[]> parameters = request
- .getParameterMap();
- if (window != null && parameters != null) {
- window.handleParameters(parameters);
- }
-
- if (requestType == RequestType.APPLICATION_RESOURCE) {
- handleURI(applicationManager, window,
- (ResourceRequest) request,
- (ResourceResponse) response);
- } else if (requestType == RequestType.RENDER) {
- writeAjaxPage((RenderRequest) request,
- (RenderResponse) response, window, application);
- } else if (requestType == RequestType.EVENT) {
- // nothing to do, listeners do all the work
- } else if (requestType == RequestType.ACTION) {
- // nothing to do, listeners do all the work
- } else {
- throw new IllegalStateException(
- "handleRequest() without anything to do - should never happen!");
- }
+ handleOtherRequest(request, response, requestType,
+ application, window, applicationContext,
+ applicationManager);
}
} catch (final SessionExpiredException e) {
// TODO Figure out a better way to deal with
@@ -494,26 +484,67 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
}
}
+ private void handleUnknownRequest(PortletRequest request,
+ PortletResponse response) {
+ System.err.println("Unknown request type");
+ }
+
/**
- * Returns a window for a portlet mode. To define custom content for a
- * portlet mode, add (in the application) a window whose name matches the
- * portlet mode name. By default, the main window is returned.
+ * Handle a portlet request that is not for static files, UIDL or upload.
+ * Also render requests are handled here.
*
- * Alternatively, a PortletListener can change the main window content.
+ * This method is called after starting the application and calling portlet
+ * and transaction listeners.
*
* @param request
+ * @param response
+ * @param requestType
* @param application
- * @return Window to show in the portlet for the given portlet mode
+ * @param applicationContext
+ * @param applicationManager
+ * @throws PortletException
+ * @throws IOException
+ * @throws MalformedURLException
*/
- protected Window getPortletWindow(PortletRequest request,
- Application application) {
- PortletMode mode = request.getPortletMode();
- Window window = application.getWindow(mode.toString());
- if (window != null) {
- return window;
+ private void handleOtherRequest(PortletRequest request,
+ PortletResponse response, RequestType requestType,
+ Application application, Window window,
+ PortletApplicationContext2 applicationContext,
+ PortletCommunicationManager applicationManager)
+ throws PortletException, IOException, MalformedURLException {
+ if (window == null) {
+ throw new PortletException(ERROR_NO_WINDOW_FOUND);
+ }
+
+ /*
+ * Sets terminal type for the window, if not already set
+ */
+ if (window.getTerminal() == null) {
+ window.setTerminal(applicationContext.getBrowser());
+ }
+
+ /*
+ * Handle parameters
+ */
+ final Map<String, String[]> parameters = request.getParameterMap();
+ if (window != null && parameters != null) {
+ window.handleParameters(parameters);
+ }
+
+ if (requestType == RequestType.APPLICATION_RESOURCE) {
+ handleURI(applicationManager, window, (ResourceRequest) request,
+ (ResourceResponse) response);
+ } else if (requestType == RequestType.RENDER) {
+ writeAjaxPage((RenderRequest) request, (RenderResponse) response,
+ window, application);
+ } else if (requestType == RequestType.EVENT) {
+ // nothing to do, listeners do all the work
+ } else if (requestType == RequestType.ACTION) {
+ // nothing to do, listeners do all the work
+ } else {
+ throw new IllegalStateException(
+ "handleRequest() without anything to do - should never happen!");
}
- // no specific window found
- return application.getMainWindow();
}
private void updateBrowserProperties(WebBrowser browser,
@@ -648,53 +679,26 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
handleRequest(request, response);
}
- /**
- * Handles a request for the "view" (default) portlet mode. In Vaadin, the
- * basic portlet modes ("view", "edit" and "help") are handled identically,
- * and their behavior can be changed by registering windows in the
- * application with window names identical to the portlet mode names.
- * Alternatively, a PortletListener can change the application main window
- * contents.
- *
- * To implement custom portlet modes, subclass the portlet class and
- * implement a method annotated with {@link RenderMode} for the custom mode,
- * calling {@link #handleRequest(PortletRequest, PortletResponse)} directly
- * from it.
- *
- * Note that the portlet class in the portlet configuration needs to be
- * changed when overriding methods of this class.
- *
- * @param request
- * @param response
- * @throws PortletException
- * @throws IOException
- */
@Override
- protected void doView(RenderRequest request, RenderResponse response)
+ protected void doDispatch(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
- handleRequest(request, response);
- }
+ try {
+ // try to let super handle - it'll call methods annotated for
+ // handling, the default doXYZ(), or throw if a handler for the mode
+ // is not found
+ super.doDispatch(request, response);
- /**
- * Handle a request for the "edit" portlet mode.
- *
- * @see #doView(RenderRequest, RenderResponse)
- */
- @Override
- protected void doEdit(RenderRequest request, RenderResponse response)
- throws PortletException, IOException {
- handleRequest(request, response);
- }
+ } catch (PortletException e) {
+ if (e.getCause() == null) {
+ // No cause interpreted as 'unknown mode' - pass that trough
+ // so that the application can handle
+ handleRequest(request, response);
- /**
- * Handle a request for the "help" portlet mode.
- *
- * @see #doView(RenderRequest, RenderResponse)
- */
- @Override
- protected void doHelp(RenderRequest request, RenderResponse response)
- throws PortletException, IOException {
- handleRequest(request, response);
+ } else {
+ // Something else failed, pass on
+ throw e;
+ }
+ }
}
@Override
@@ -833,17 +837,63 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
return null;
}
+ /**
+ * Returns the URL from which the widgetset is served on the portal.
+ *
+ * @param widgetset
+ * @param request
+ * @return
+ */
protected String getWidgetsetURL(String widgetset, PortletRequest request) {
return getStaticFilesLocation(request) + "/" + WIDGETSET_DIRECTORY_PATH
+ widgetset + "/" + widgetset + ".nocache.js?"
+ new Date().getTime();
}
+ /**
+ * Returns the theme URI for the named theme on the portal.
+ *
+ * Note that this is not the only location referring to the theme URI - also
+ * e.g. PortletCommunicationManager uses its own way to access the portlet
+ * 2.0 theme resources.
+ *
+ * @param themeName
+ * @param request
+ * @return
+ */
protected String getThemeURI(String themeName, PortletRequest request) {
return getStaticFilesLocation(request) + "/" + THEME_DIRECTORY_PATH
+ themeName;
}
+ /**
+ * Writes the html host page (aka kickstart page) that starts the actual
+ * Vaadin application.
+ *
+ * If one needs to override parts of the portlet HTML contents creation, it
+ * is suggested that one overrides one of several submethods including:
+ * <ul>
+ * <li>
+ * {@link #writeAjaxPageHtmlMainDiv(RenderRequest, RenderResponse, BufferedWriter, String)}
+ * <li>
+ * {@link #getVaadinConfigurationMap(RenderRequest, RenderResponse, Application, String)}
+ * <li>
+ * {@link #writeAjaxPageHtmlVaadinScripts(RenderRequest, RenderResponse, BufferedWriter, Application, String)}
+ * </ul>
+ *
+ * @param request
+ * the portlet request.
+ * @param response
+ * the portlet response to write to.
+ * @param window
+ * @param application
+ * @throws IOException
+ * if the writing failed due to input/output error.
+ * @throws MalformedURLException
+ * if the application is denied access the persistent data store
+ * represented by the given URL.
+ * @throws PortletException
+ */
protected void writeAjaxPage(RenderRequest request,
RenderResponse response, Window window, Application application)
throws IOException, MalformedURLException, PortletException {
@@ -852,27 +902,62 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
final BufferedWriter page = new BufferedWriter(new OutputStreamWriter(
response.getPortletOutputStream(), "UTF-8"));
- // TODO check
- String requestWidgetset = getApplicationOrSystemProperty(
- PARAMETER_WIDGETSET, null);
- String sharedWidgetset = getPortalProperty(
- PORTAL_PARAMETER_VAADIN_WIDGETSET, request.getPortalContext());
-
- String widgetset;
- if (requestWidgetset != null) {
- widgetset = requestWidgetset;
- } else if (sharedWidgetset != null) {
- widgetset = sharedWidgetset;
- } else {
- widgetset = DEFAULT_WIDGETSET;
- }
-
// TODO Currently, we can only load widgetsets and themes from the
// portal
String themeName = getThemeForWindow(request, window);
- String widgetsetURL = getWidgetsetURL(widgetset, request);
+ writeAjaxPageHtmlVaadinScripts(request, response, page, application,
+ themeName);
+
+ /*- Add classnames;
+ * .v-app
+ * .v-app-loading
+ * .v-app-<simpleName for app class>
+ * .v-theme-<themeName, remove non-alphanum>
+ */
+ String appClass = "v-app-";
+ try {
+ appClass += getApplicationClass().getSimpleName();
+ } catch (ClassNotFoundException e) {
+ appClass += "unknown";
+ e.printStackTrace();
+ }
+ String themeClass = "v-theme-"
+ + themeName.replaceAll("[^a-zA-Z0-9]", "");
+
+ String classNames = "v-app v-app-loading " + themeClass + " "
+ + appClass;
+
+ String style = getApplicationProperty(PORTLET_PARAMETER_STYLE);
+ String divStyle = "";
+ if (style != null) {
+ divStyle = "style=\"" + style + "\"";
+ }
+
+ writeAjaxPageHtmlMainDiv(request, response, page,
+ request.getWindowID(), classNames, divStyle);
+
+ page.close();
+ }
+
+ /**
+ * This method writes the scripts to load the widgetset and the themes as
+ * well as define Vaadin configuration parameters on the HTML fragment that
+ * starts the actual Vaadin application.
+ *
+ * @param request
+ * @param response
+ * @param writer
+ * @param application
+ * @param themeName
+ * @throws IOException
+ * @throws PortletException
+ */
+ protected void writeAjaxPageHtmlVaadinScripts(RenderRequest request,
+ RenderResponse response, final BufferedWriter writer,
+ Application application, String themeName) throws IOException,
+ PortletException {
String themeURI = getThemeURI(themeName, request);
// fixed base theme to use - all portal pages with Vaadin
@@ -880,52 +965,113 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
String portalTheme = getPortalProperty(PORTAL_PARAMETER_VAADIN_THEME,
request.getPortalContext());
- // Get system messages
- Application.SystemMessages systemMessages = null;
- try {
- systemMessages = getSystemMessages();
- } catch (SystemMessageException e) {
- // failing to get the system messages is always a problem
- throw new PortletException("Failed to obtain system messages!", e);
- }
-
- page.write("<script type=\"text/javascript\">\n");
- page.write("if(!vaadin || !vaadin.vaadinConfigurations) {\n "
+ writer.write("<script type=\"text/javascript\">\n");
+ writer.write("if(!vaadin || !vaadin.vaadinConfigurations) {\n "
+ "if(!vaadin) { var vaadin = {}} \n"
+ "vaadin.vaadinConfigurations = {};\n"
+ "if (!vaadin.themesLoaded) { vaadin.themesLoaded = {}; }\n");
if (!isProductionMode()) {
- page.write("vaadin.debug = true;\n");
+ writer.write("vaadin.debug = true;\n");
}
- page
+
+ writeAjaxPageScriptWidgetset(request, response, writer);
+
+ Map<String, String> config = getVaadinConfigurationMap(request,
+ response, application, themeURI);
+ writeAjaxPageScriptConfigurations(request, response, writer, config);
+
+ writer.write("</script>\n");
+
+ writeAjaxPageHtmlTheme(request, writer, themeName, themeURI,
+ portalTheme);
+
+ // TODO Warn if widgetset has not been loaded after 15 seconds
+ }
+
+ /**
+ * Writes the script to load the widgetset on the HTML fragment created by
+ * the portlet.
+ *
+ * @param request
+ * @param response
+ * @param writer
+ * @throws IOException
+ */
+ protected void writeAjaxPageScriptWidgetset(RenderRequest request,
+ RenderResponse response, final BufferedWriter writer)
+ throws IOException {
+ String requestWidgetset = getApplicationOrSystemProperty(
+ PARAMETER_WIDGETSET, null);
+ String sharedWidgetset = getPortalProperty(
+ PORTAL_PARAMETER_VAADIN_WIDGETSET, request.getPortalContext());
+
+ String widgetset;
+ if (requestWidgetset != null) {
+ widgetset = requestWidgetset;
+ } else if (sharedWidgetset != null) {
+ widgetset = sharedWidgetset;
+ } else {
+ widgetset = DEFAULT_WIDGETSET;
+ }
+ String widgetsetURL = getWidgetsetURL(widgetset, request);
+ writer
.write("document.write('<iframe tabIndex=\"-1\" id=\"__gwt_historyFrame\" "
+ "style=\"width:0;height:0;border:0;overflow:"
+ "hidden\" src=\"javascript:false\"></iframe>');\n");
- page.write("document.write(\"<script language='javascript' src='"
+ writer.write("document.write(\"<script language='javascript' src='"
+ widgetsetURL + "'><\\/script>\");\n}\n");
+ }
- page.write("vaadin.vaadinConfigurations[\"" + request.getWindowID()
- + "\"] = {");
+ /**
+ * Returns the configuration parameters to pass to the client.
+ *
+ * To add configuration parameters for the client, override, call the super
+ * method and then modify the map. Overriding this method may also require
+ * client side changes in {@link ApplicationConnection} and
+ * {@link ApplicationConfiguration}.
+ *
+ * Note that this method must escape and quote the values when appropriate.
+ *
+ * The map returned is typically a {@link LinkedHashMap} to preserve
+ * insertion order, but it is not guaranteed to be one.
+ *
+ * @param request
+ * @param response
+ * @param application
+ * @param themeURI
+ * @return modifiable Map from parameter name to its full value
+ * @throws PortletException
+ */
+ protected Map<String, String> getVaadinConfigurationMap(
+ RenderRequest request, RenderResponse response,
+ Application application, String themeURI) throws PortletException {
+ Map<String, String> config = new LinkedHashMap<String, String>();
/*
* We need this in order to get uploads to work.
*/
PortletURL appUri = response.createActionURL();
-
- page.write("appUri: '" + appUri.toString() + "', ");
- page.write("usePortletURLs: true, ");
-
+ config.put("appUri", "'" + appUri.toString() + "'");
+ config.put("usePortletURLs", "true");
ResourceURL uidlUrlBase = response.createResourceURL();
uidlUrlBase.setResourceID("UIDL");
+ config.put("portletUidlURLBase", "'" + uidlUrlBase.toString() + "'");
+ config.put("pathInfo", "''");
+ config.put("themeUri", "'" + themeURI + "'");
+
+ String versionInfo = "{vaadinVersion:\""
+ + AbstractApplicationServlet.VERSION
+ + "\",applicationVersion:\"" + application.getVersion() + "\"}";
+ config.put("versionInfo", versionInfo);
- page.write("portletUidlURLBase: '" + uidlUrlBase.toString() + "', ");
- page.write("pathInfo: '', ");
- page.write("themeUri: '" + themeURI + "', ");
- page.write("versionInfo : {vaadinVersion:\"");
- page.write(AbstractApplicationServlet.VERSION);
- page.write("\",applicationVersion:\"");
- page.write(application.getVersion());
- page.write("\"},");
+ // Get system messages
+ Application.SystemMessages systemMessages = null;
+ try {
+ systemMessages = getSystemMessages();
+ } catch (SystemMessageException e) {
+ // failing to get the system messages is always a problem
+ throw new PortletException("Failed to obtain system messages!", e);
+ }
if (systemMessages != null) {
// Write the CommunicationError -message to client
String caption = systemMessages.getCommunicationErrorCaption();
@@ -941,73 +1087,117 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
url = "\"" + url + "\"";
}
- page.write("\"comErrMsg\": {" + "\"caption\":" + caption + ","
+ config.put("\"comErrMsg\"", "{" + "\"caption\":" + caption + ","
+ "\"message\" : " + message + "," + "\"url\" : " + url
+ "}");
}
- page.write("};\n</script>\n");
- page.write("<script type=\"text/javascript\">\n");
+ return config;
+ }
+
+ /**
+ * Constructs the Vaadin configuration section for
+ * {@link ApplicationConnection} and {@link ApplicationConfiguration}.
+ *
+ * Typically this method should not be overridden. Instead, modify
+ * {@link #getVaadinConfigurationMap(RenderRequest, RenderResponse, Application, String)}
+ * .
+ *
+ * @param request
+ * @param response
+ * @param writer
+ * @param config
+ * @throws IOException
+ * @throws PortletException
+ */
+ protected void writeAjaxPageScriptConfigurations(RenderRequest request,
+ RenderResponse response, final BufferedWriter writer,
+ Map<String, String> config) throws IOException, PortletException {
+
+ writer.write("vaadin.vaadinConfigurations[\"" + request.getWindowID()
+ + "\"] = {");
+
+ Iterator<String> keyIt = config.keySet().iterator();
+ while (keyIt.hasNext()) {
+ String key = keyIt.next();
+ writer.write(key + ": " + config.get(key));
+ if (keyIt.hasNext()) {
+ writer.write(", ");
+ }
+ }
+
+ writer.write("};\n");
+ }
+
+ /**
+ * Writes the Vaadin theme loading section of the portlet HTML. Loads both
+ * the portal theme and the portlet theme in this order, skipping loading of
+ * themes that are already loaded (matched by name).
+ *
+ * @param request
+ * @param writer
+ * @param themeName
+ * @param themeURI
+ * @param portalTheme
+ * @throws IOException
+ */
+ protected void writeAjaxPageHtmlTheme(RenderRequest request,
+ final BufferedWriter writer, String themeName, String themeURI,
+ String portalTheme) throws IOException {
+ writer.write("<script type=\"text/javascript\">\n");
if (portalTheme == null) {
portalTheme = DEFAULT_THEME_NAME;
}
- page.write("if(!vaadin.themesLoaded['" + portalTheme + "']) {\n");
- page.write("var defaultStylesheet = document.createElement('link');\n");
- page.write("defaultStylesheet.setAttribute('rel', 'stylesheet');\n");
- page.write("defaultStylesheet.setAttribute('type', 'text/css');\n");
- page.write("defaultStylesheet.setAttribute('href', '"
+ writer.write("if(!vaadin.themesLoaded['" + portalTheme + "']) {\n");
+ writer
+ .write("var defaultStylesheet = document.createElement('link');\n");
+ writer.write("defaultStylesheet.setAttribute('rel', 'stylesheet');\n");
+ writer.write("defaultStylesheet.setAttribute('type', 'text/css');\n");
+ writer.write("defaultStylesheet.setAttribute('href', '"
+ getThemeURI(portalTheme, request) + "/styles.css');\n");
- page
+ writer
.write("document.getElementsByTagName('head')[0].appendChild(defaultStylesheet);\n");
- page.write("vaadin.themesLoaded['" + portalTheme + "'] = true;\n}\n");
+ writer.write("vaadin.themesLoaded['" + portalTheme + "'] = true;\n}\n");
if (!portalTheme.equals(themeName)) {
- page.write("if(!vaadin.themesLoaded['" + themeName + "']) {\n");
- page.write("var stylesheet = document.createElement('link');\n");
- page.write("stylesheet.setAttribute('rel', 'stylesheet');\n");
- page.write("stylesheet.setAttribute('type', 'text/css');\n");
- page.write("stylesheet.setAttribute('href', '" + themeURI
+ writer.write("if(!vaadin.themesLoaded['" + themeName + "']) {\n");
+ writer.write("var stylesheet = document.createElement('link');\n");
+ writer.write("stylesheet.setAttribute('rel', 'stylesheet');\n");
+ writer.write("stylesheet.setAttribute('type', 'text/css');\n");
+ writer.write("stylesheet.setAttribute('href', '" + themeURI
+ "/styles.css');\n");
- page
+ writer
.write("document.getElementsByTagName('head')[0].appendChild(stylesheet);\n");
- page.write("vaadin.themesLoaded['" + themeName + "'] = true;\n}\n");
- }
-
- page.write("</script>\n");
-
- // TODO Warn if widgetset has not been loaded after 15 seconds
-
- /*- Add classnames;
- * .v-app
- * .v-app-loading
- * .v-app-<simpleName for app class>
- * .v-theme-<themeName, remove non-alphanum>
- */
-
- String appClass = "v-app-";
- try {
- appClass += getApplicationClass().getSimpleName();
- } catch (ClassNotFoundException e) {
- appClass += "unknown";
- e.printStackTrace();
+ writer.write("vaadin.themesLoaded['" + themeName
+ + "'] = true;\n}\n");
}
- String themeClass = "v-theme-"
- + themeName.replaceAll("[^a-zA-Z0-9]", "");
- String classNames = "v-app v-app-loading " + themeClass + " "
- + appClass;
+ writer.write("</script>\n");
+ }
- String style = getApplicationProperty(PORTLET_PARAMETER_STYLE);
- String divStyle = "";
- if (style != null) {
- divStyle = "style=\"" + style + "\"";
- }
- page.write("<div id=\"" + request.getWindowID() + "\" class=\""
+ /**
+ * Method to write the div element into which that actual Vaadin application
+ * is rendered.
+ * <p>
+ * Override this method if you want to add some custom html around around
+ * the div element into which the actual Vaadin application will be
+ * rendered.
+ *
+ * @param request
+ * @param response
+ * @param writer
+ * @param id
+ * @param classNames
+ * @param divStyle
+ * @throws IOException
+ */
+ protected void writeAjaxPageHtmlMainDiv(RenderRequest request,
+ RenderResponse response, final BufferedWriter writer, String id,
+ String classNames, String divStyle) throws IOException {
+ writer.write("<div id=\"" + id + "\" class=\""
+ classNames + "\" " + divStyle + "></div>\n");
-
- page.close();
}
/**
@@ -1017,7 +1207,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
* @param window
* @return
*/
- private String getThemeForWindow(PortletRequest request, Window window) {
+ protected String getThemeForWindow(PortletRequest request, Window window) {
// Finds theme name
String themeName;
@@ -1189,12 +1379,21 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
+ "\"appError\": {" + "\"caption\":" + caption + ","
+ "\"message\" : " + message + "," + "\"url\" : " + url
+ "}}, \"resources\": {}, \"locales\":[]}]");
- outWriter.flush();
outWriter.close();
- out.flush();
}
- private static String getPortalProperty(String name, PortalContext context) {
+ /**
+ * Returns a portal configuration property.
+ *
+ * Liferay is handled separately as
+ * {@link PortalContext#getProperty(String)} does not return portal
+ * properties from e.g. portal-ext.properties .
+ *
+ * @param name
+ * @param context
+ * @return
+ */
+ protected static String getPortalProperty(String name, PortalContext context) {
boolean isLifeRay = context.getPortalInfo().toLowerCase().contains(
"liferay");
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
index 7a3978f323..8c901ba7e7 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
@@ -362,6 +362,9 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
HttpServletResponse response) throws ServletException, IOException {
RequestType requestType = getRequestType(request);
+ if (!ensureCookiesEnabled(requestType, request, response)) {
+ return;
+ }
if (requestType == RequestType.STATIC_FILE) {
serveStaticResources(request, response);
@@ -435,7 +438,10 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
return;
} else if (requestType == RequestType.UIDL) {
// Handles AJAX UIDL requests
- applicationManager.handleUidlRequest(request, response, this);
+ Window window = applicationManager.getApplicationWindow(
+ request, this, application, null);
+ applicationManager.handleUidlRequest(request, response, this,
+ window);
return;
}
@@ -502,6 +508,39 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
}
+ /**
+ * Check that cookie support is enabled in the browser. Only checks UIDL
+ * requests.
+ *
+ * @param requestType
+ * Type of the request as returned by
+ * {@link #getRequestType(HttpServletRequest)}
+ * @param request
+ * The request from the browser
+ * @param response
+ * The response to which an error can be written
+ * @return false if cookies are disabled, true otherwise
+ * @throws IOException
+ */
+ private boolean ensureCookiesEnabled(RequestType requestType,
+ HttpServletRequest request, HttpServletResponse response)
+ throws IOException {
+ if (requestType == RequestType.UIDL && !isRepaintAll(request)) {
+ // In all other but the first UIDL request a cookie should be
+ // returned by the browser.
+ // This can be removed if cookieless mode (#3228) is supported
+ if (request.getRequestedSessionId() == null) {
+ // User has cookies disabled
+ criticalNotification(request, response, getSystemMessages()
+ .getCookiesDisabledCaption(), getSystemMessages()
+ .getCookiesDisabledMessage(), null, getSystemMessages()
+ .getCookiesDisabledURL());
+ return false;
+ }
+ }
+ return true;
+ }
+
private void updateBrowserProperties(WebBrowser browser,
HttpServletRequest request) {
browser.updateBrowserProperties(request.getLocale(), request
@@ -535,38 +574,40 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
/**
- * Send notification to client's application. Used to notify client of
- * critical errors and session expiration due to long inactivity. Server has
- * no knowledge of what application client refers to.
+ * Send a notification to client's application. Used to notify client of
+ * critical errors, session expiration and more. Server has no knowledge of
+ * what application client refers to.
*
* @param request
* the HTTP request instance.
* @param response
* the HTTP response to write to.
* @param caption
- * for the notification
+ * the notification caption
* @param message
- * for the notification
+ * to notification body
* @param details
- * a detail message to show in addition to the passed message.
- * Currently shown directly but could be hidden behind a details
- * drop down.
+ * a detail message to show in addition to the message. Currently
+ * shown directly below the message but could be hidden behind a
+ * details drop down in the future. Mainly used to give
+ * additional information not necessarily useful to the end user.
* @param url
- * url to load after message, null for current page
+ * url to load when the message is dismissed. Null will reload
+ * the current page.
* @throws IOException
* if the writing failed due to input/output error.
*/
- void criticalNotification(HttpServletRequest request,
+ protected final void criticalNotification(HttpServletRequest request,
HttpServletResponse response, String caption, String message,
String details, String url) throws IOException {
- // clients JS app is still running, but server application either
- // no longer exists or it might fail to perform reasonably.
- // send a notification to client's application and link how
- // to "restart" application.
+ if (!isUIDLRequest(request)) {
+ throw new RuntimeException(
+ "criticalNotification can only be used in UIDL requests");
+ }
if (caption != null) {
- caption = "\"" + caption + "\"";
+ caption = "\"" + JsonPaintTarget.escapeJSON(caption) + "\"";
}
if (details != null) {
if (message == null) {
@@ -575,11 +616,12 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
message += "<br/><br/>" + details;
}
}
+
if (message != null) {
- message = "\"" + message + "\"";
+ message = "\"" + JsonPaintTarget.escapeJSON(message) + "\"";
}
if (url != null) {
- url = "\"" + url + "\"";
+ url = "\"" + JsonPaintTarget.escapeJSON(url) + "\"";
}
// Set the response type
@@ -1489,7 +1531,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
* is rendered.
* <p>
* Override this method if you want to add some custom html around around
- * the div element into which the actual vaadin application will be
+ * the div element into which the actual Vaadin application will be
* rendered.
*
* @param page
@@ -1507,8 +1549,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
/**
- *
- * * Method to write the script part of the page which loads needed vaadin
+ * Method to write the script part of the page which loads needed Vaadin
* scripts and themes.
* <p>
* Override this method if you want to add some custom html around scripts.
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
index 67b806f0f0..481e42c0e9 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
@@ -498,11 +498,14 @@ public abstract class AbstractCommunicationManager implements
* @param request
* @param response
* @param callback
+ * @param window
+ * target window for the UIDL request, can be null if target not
+ * found
* @throws IOException
* @throws InvalidUIDLSecurityKeyException
*/
protected void doHandleUidlRequest(Request request, Response response,
- Callback callback) throws IOException,
+ Callback callback, Window window) throws IOException,
InvalidUIDLSecurityKeyException {
// repaint requested or session has timed out and new one is created
@@ -528,10 +531,7 @@ public abstract class AbstractCommunicationManager implements
synchronized (application) {
// Finds the window within the application
- Window window = null;
if (application.isRunning()) {
- window = doGetApplicationWindow(request, callback, application,
- null);
// Returns if no window found
if (window == null) {
// This should not happen, no windows exists but
@@ -588,8 +588,7 @@ public abstract class AbstractCommunicationManager implements
}
}
- // out.flush(); - this line will cause errors when deployed on GateIn.
- out.close();
+ outWriter.close();
}
/**
@@ -947,7 +946,6 @@ public abstract class AbstractCommunicationManager implements
outWriter.print("}]");
}
- outWriter.flush();
outWriter.close();
}
@@ -1871,7 +1869,7 @@ public abstract class AbstractCommunicationManager implements
}
return stream;
} else {
- // Resolve the prefix end inded
+ // Resolve the prefix end index
final int index = uri.indexOf('/');
if (index > 0) {
String prefix = uri.substring(0, index);
diff --git a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java
index 8799e37899..4e6bfbd158 100644
--- a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java
+++ b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java
@@ -238,16 +238,22 @@ public class CommunicationManager extends AbstractCommunicationManager {
*
* @param request
* @param response
+ * @param applicationServlet
+ * @param window
+ * target window of the UIDL request, can be null if window not
+ * found
* @throws IOException
* @throws ServletException
*/
public void handleUidlRequest(HttpServletRequest request,
HttpServletResponse response,
- AbstractApplicationServlet applicationServlet) throws IOException,
- ServletException, InvalidUIDLSecurityKeyException {
+ AbstractApplicationServlet applicationServlet, Window window)
+ throws IOException, ServletException,
+ InvalidUIDLSecurityKeyException {
doHandleUidlRequest(new HttpServletRequestWrapper(request),
new HttpServletResponseWrapper(response),
- new AbstractApplicationServletWrapper(applicationServlet));
+ new AbstractApplicationServletWrapper(applicationServlet),
+ window);
}
/**
diff --git a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
index ab1b1da81f..a6f8d7f204 100644
--- a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
+++ b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
@@ -139,18 +139,18 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
}
}
- public void firePortletRenderRequest(Application app,
+ public void firePortletRenderRequest(Application app, Window window,
RenderRequest request, RenderResponse response) {
Set<PortletListener> listeners = portletListeners.get(app);
if (listeners != null) {
for (PortletListener l : listeners) {
l.handleRenderRequest(request, new RestrictedRenderResponse(
- response));
+ response), window);
}
}
}
- public void firePortletActionRequest(Application app,
+ public void firePortletActionRequest(Application app, Window window,
ActionRequest request, ActionResponse response) {
String key = request.getParameter(ActionRequest.ACTION_NAME);
if (eventActionDestinationMap.containsKey(key)) {
@@ -172,28 +172,28 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
Set<PortletListener> listeners = portletListeners.get(app);
if (listeners != null) {
for (PortletListener l : listeners) {
- l.handleActionRequest(request, response);
+ l.handleActionRequest(request, response, window);
}
}
}
}
- public void firePortletEventRequest(Application app, EventRequest request,
- EventResponse response) {
+ public void firePortletEventRequest(Application app, Window window,
+ EventRequest request, EventResponse response) {
Set<PortletListener> listeners = portletListeners.get(app);
if (listeners != null) {
for (PortletListener l : listeners) {
- l.handleEventRequest(request, response);
+ l.handleEventRequest(request, response, window);
}
}
}
- public void firePortletResourceRequest(Application app,
+ public void firePortletResourceRequest(Application app, Window window,
ResourceRequest request, ResourceResponse response) {
Set<PortletListener> listeners = portletListeners.get(app);
if (listeners != null) {
for (PortletListener l : listeners) {
- l.handleResourceRequest(request, response);
+ l.handleResourceRequest(request, response, window);
}
}
}
@@ -201,16 +201,16 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
public interface PortletListener extends Serializable {
public void handleRenderRequest(RenderRequest request,
- RenderResponse response);
+ RenderResponse response, Window window);
public void handleActionRequest(ActionRequest request,
- ActionResponse response);
+ ActionResponse response, Window window);
public void handleEventRequest(EventRequest request,
- EventResponse response);
+ EventResponse response, Window window);
public void handleResourceRequest(ResourceRequest request,
- ResourceResponse response);
+ ResourceResponse response, Window window);
}
/**
diff --git a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
index 3a5cd90f7c..7fe324b1db 100644
--- a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
+++ b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
@@ -3,6 +3,7 @@ package com.vaadin.terminal.gwt.server;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.reflect.Method;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
@@ -13,6 +14,8 @@ import javax.portlet.PortletResponse;
import javax.portlet.PortletSession;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequestWrapper;
import com.vaadin.Application;
import com.vaadin.external.org.apache.commons.fileupload.FileItemIterator;
@@ -54,7 +57,20 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
}
public String getParameter(String name) {
- return request.getParameter(name);
+ String value = request.getParameter(name);
+ if (value == null) {
+ // for GateIn portlet container simple-portal
+ try {
+ Method getRealReq = request.getClass().getMethod(
+ "getRealRequest");
+ HttpServletRequestWrapper origRequest = (HttpServletRequestWrapper) getRealReq
+ .invoke(request);
+ value = origRequest.getParameter(name);
+ } catch (Exception e) {
+ // do nothing - not on GateIn simple-portal
+ }
+ }
+ return value;
}
public String getRequestID() {
@@ -165,19 +181,6 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
+ themeName + "/" + resource);
}
- /**
- * Find the application window to use based on the portlet mode. For
- * internal use only, not in the {@link Callback} interface.
- *
- * @param request
- * @param application
- * @return
- */
- public Window getPortletWindow(PortletRequest request,
- Application application) {
- return portlet.getPortletWindow(request, application);
- }
-
}
public PortletCommunicationManager(Application application) {
@@ -222,11 +225,12 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
public void handleUidlRequest(ResourceRequest request,
ResourceResponse response,
- AbstractApplicationPortlet applicationPortlet)
+ AbstractApplicationPortlet applicationPortlet, Window window)
throws InvalidUIDLSecurityKeyException, IOException {
doHandleUidlRequest(new PortletRequestWrapper(request),
new PortletResponseWrapper(response),
- new AbstractApplicationPortletWrapper(applicationPortlet));
+ new AbstractApplicationPortletWrapper(applicationPortlet),
+ window);
}
DownloadStream handleURI(Window window, ResourceRequest request,
@@ -237,18 +241,29 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
new AbstractApplicationPortletWrapper(applicationPortlet));
}
- @Override
- protected Window doGetApplicationWindow(Request request, Callback callback,
+ /**
+ * Gets the existing application or creates a new one. Get a window within
+ * an application based on the requested URI.
+ *
+ * @param request
+ * the portlet Request.
+ * @param applicationPortlet
+ * @param application
+ * the Application to query for window.
+ * @param assumedWindow
+ * if the window has been already resolved once, this parameter
+ * must contain the window.
+ * @return Window matching the given URI or null if not found.
+ * @throws ServletException
+ * if an exception has occurred that interferes with the
+ * servlet's normal operation.
+ */
+ Window getApplicationWindow(PortletRequest request,
+ AbstractApplicationPortlet applicationPortlet,
Application application, Window assumedWindow) {
- // find window based on portlet mode
- if (assumedWindow == null
- && callback instanceof AbstractApplicationPortletWrapper
- && request.getWrappedRequest() instanceof PortletRequest) {
- assumedWindow = ((AbstractApplicationPortletWrapper) callback)
- .getPortletWindow((PortletRequest) request
- .getWrappedRequest(), application);
- }
- return super.doGetApplicationWindow(request, callback, application,
- assumedWindow);
+ return doGetApplicationWindow(new PortletRequestWrapper(request),
+ new AbstractApplicationPortletWrapper(applicationPortlet),
+ application, assumedWindow);
}
+
}
diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java b/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java
index b3c670ba81..ca20b8b895 100644
--- a/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java
+++ b/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java
@@ -19,7 +19,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.TreeSet;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -175,7 +174,9 @@ public class ClassPathExplorer {
for (int i = 0; i < widgetsetNames.length; i++) {
String widgetsetname = widgetsetNames[i].trim()
.intern();
- widgetsets.put(widgetsetname, location);
+ if (!widgetsetname.equals("")) {
+ widgetsets.put(widgetsetname, location);
+ }
}
}
}
@@ -439,8 +440,15 @@ public class ClassPathExplorer {
* @return URL
*/
public static URL getDefaultSourceDirectory() {
- logger.fine("classpathLocations keys: "
- + new TreeSet<URL>(classpathLocations.keySet()));
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("classpathLocations keys:");
+ ArrayList<URL> locations = new ArrayList<URL>(classpathLocations
+ .keySet());
+ for (URL location : locations) {
+ logger.fine(location.toString());
+ }
+ }
+
Iterator<String> it = rawClasspathEntries.iterator();
while (it.hasNext()) {
String entry = it.next();
diff --git a/src/com/vaadin/ui/Button.java b/src/com/vaadin/ui/Button.java
index 3ed50b2d42..65a34a18bb 100644
--- a/src/com/vaadin/ui/Button.java
+++ b/src/com/vaadin/ui/Button.java
@@ -13,6 +13,7 @@ import com.vaadin.data.Property;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.gwt.client.ui.VButton;
+import com.vaadin.ui.themes.BaseTheme;
/**
* A generic button component.
@@ -239,7 +240,12 @@ public class Button extends AbstractField {
private static final Method BUTTON_CLICK_METHOD;
- /* Button style with no decorations. Looks like a link, acts like a button */
+ /**
+ * Button style with no decorations. Looks like a link, acts like a button
+ *
+ * @deprecated use {@link BaseTheme#BUTTON_LINK} instead.
+ */
+ @Deprecated
public static final String STYLE_LINK = "link";
static {
diff --git a/src/com/vaadin/ui/Form.java b/src/com/vaadin/ui/Form.java
index c6c9a5a738..678c323dc3 100644
--- a/src/com/vaadin/ui/Form.java
+++ b/src/com/vaadin/ui/Form.java
@@ -479,54 +479,99 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item,
return false;
}
+ // Register and attach the created field
addField(id, field);
return true;
}
/**
- * Adds the field to form.
+ * Registers the field with the form and adds the field to the form layout.
*
* <p>
* The property id must not be already used in the form.
* </p>
*
* <p>
- * This field is added to the form layout in the default position (the
- * position used by {@link Layout#addComponent(Component)} method. In the
- * special case that the underlying layout is a custom layout, string
- * representation of the property id is used instead of the default
- * location.
+ * This field is added to the layout using the
+ * {@link #attachField(Object, Field)} method.
* </p>
*
* @param propertyId
* the Property id the the field.
* @param field
- * the New field added to the form.
+ * the field which should be added to the form.
*/
public void addField(Object propertyId, Field field) {
+ registerField(propertyId, field);
+ attachField(propertyId, field);
+ requestRepaint();
+ }
- if (propertyId != null && field != null) {
- fields.put(propertyId, field);
- field.addListener(fieldValueChangeListener);
- if (!propertyIds.contains(propertyId)) {
- // adding a field directly
- propertyIds.addLast(propertyId);
- }
- field.setReadThrough(readThrough);
- field.setWriteThrough(writeThrough);
- if (isImmediate() && field instanceof AbstractComponent) {
- ((AbstractComponent) field).setImmediate(true);
- }
- if (layout instanceof CustomLayout) {
- ((CustomLayout) layout).addComponent(field, propertyId
- .toString());
- } else {
- layout.addComponent(field);
- }
+ /**
+ * Register the field with the form. All registered fields are validated
+ * when the form is validated and also committed when the form is committed.
+ *
+ * <p>
+ * The property id must not be already used in the form.
+ * </p>
+ *
+ *
+ * @param propertyId
+ * the Property id of the field.
+ * @param field
+ * the Field that should be registered
+ */
+ private void registerField(Object propertyId, Field field) {
+ if (propertyId == null || field == null) {
+ return;
+ }
- requestRepaint();
+ fields.put(propertyId, field);
+ field.addListener(fieldValueChangeListener);
+ if (!propertyIds.contains(propertyId)) {
+ // adding a field directly
+ propertyIds.addLast(propertyId);
}
+
+ // Update the read and write through status and immediate to match the
+ // form.
+ // Should this also include invalidCommitted (#3993)?
+ field.setReadThrough(readThrough);
+ field.setWriteThrough(writeThrough);
+ if (isImmediate() && field instanceof AbstractComponent) {
+ ((AbstractComponent) field).setImmediate(true);
+ }
+ }
+
+ /**
+ * Adds the field to the form layout.
+ * <p>
+ * The field is added to the form layout in the default position (the
+ * position used by {@link Layout#addComponent(Component)}. If the
+ * underlying layout is a {@link CustomLayout} the field is added to the
+ * CustomLayout location given by the string representation of the property
+ * id using {@link CustomLayout#addComponent(Component, String)}.
+ * </p>
+ *
+ * <p>
+ * Override this method to control how the fields are added to the layout.
+ * </p>
+ *
+ * @param propertyId
+ * @param field
+ */
+ protected void attachField(Object propertyId, Field field) {
+ if (propertyId == null || field == null) {
+ return;
+ }
+
+ if (layout instanceof CustomLayout) {
+ ((CustomLayout) layout).addComponent(field, propertyId.toString());
+ } else {
+ layout.addComponent(field);
+ }
+
}
/**
diff --git a/src/com/vaadin/ui/Panel.java b/src/com/vaadin/ui/Panel.java
index df08c4e62b..f4ce352687 100644
--- a/src/com/vaadin/ui/Panel.java
+++ b/src/com/vaadin/ui/Panel.java
@@ -19,6 +19,8 @@ import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Scrollable;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.VPanel;
+import com.vaadin.ui.themes.Reindeer;
+import com.vaadin.ui.themes.Runo;
/**
* Panel - a simple single component container.
@@ -36,6 +38,16 @@ public class Panel extends AbstractComponentContainer implements Scrollable,
private static final String CLICK_EVENT = VPanel.CLICK_EVENT_IDENTIFIER;
+ /**
+ * Removes extra decorations from the Panel.
+ *
+ * @deprecated this style is no longer part of the core framework and this
+ * component, even though most built-in themes implement this
+ * style. Use the constant specified in the theme class file
+ * that you're using, if it provides one, e.g.
+ * {@link Reindeer#PANEL_LIGHT} or {@link Runo#PANEL_LIGHT} .
+ */
+ @Deprecated
public static final String STYLE_LIGHT = "light";
/**
diff --git a/src/com/vaadin/ui/SplitPanel.java b/src/com/vaadin/ui/SplitPanel.java
index 5e67b93369..1a149d7394 100644
--- a/src/com/vaadin/ui/SplitPanel.java
+++ b/src/com/vaadin/ui/SplitPanel.java
@@ -281,10 +281,11 @@ public class SplitPanel extends AbstractLayout {
* Moves the position of the splitter.
*
* @param pos
- * the new size of the first region in percentage
+ * the new size of the first region in the unit that was last
+ * used (default is percentage)
*/
public void setSplitPosition(int pos) {
- setSplitPosition(pos, UNITS_PERCENTAGE, true);
+ setSplitPosition(pos, posUnit, true);
}
/**
@@ -303,7 +304,7 @@ public class SplitPanel extends AbstractLayout {
* Moves the position of the splitter.
*
* @param pos
- * the new size of the first region in percentage
+ * the new size of the first region
* @param unit
* the unit (from {@link Sizeable}) in which the size is given.
* @param repaintNotNeeded
@@ -312,6 +313,10 @@ public class SplitPanel extends AbstractLayout {
* knows the position.
*/
private void setSplitPosition(int pos, int unit, boolean repaintNeeded) {
+ if (unit != UNITS_PERCENTAGE && unit != UNITS_PIXELS) {
+ throw new IllegalArgumentException(
+ "Only percentage and pixel units are allowed");
+ }
this.pos = pos;
posUnit = unit;
if (repaintNeeded) {
@@ -353,8 +358,7 @@ public class SplitPanel extends AbstractLayout {
if (variables.containsKey("position") && !isLocked()) {
Integer newPos = (Integer) variables.get("position");
- // Client always sends pixel values. Repaint is not needed.
- setSplitPosition(newPos, UNITS_PIXELS, false);
+ setSplitPosition(newPos, posUnit, false);
}
if (variables.containsKey(SPLITTER_CLICK_EVENT)) {
diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java
index 9246067541..753a52a3de 100644
--- a/src/com/vaadin/ui/Table.java
+++ b/src/com/vaadin/ui/Table.java
@@ -40,14 +40,20 @@ import com.vaadin.terminal.gwt.client.ui.VScrollTable;
/**
* <p>
- * <code>TableComponent</code> is used for representing data or components in
- * pageable and selectable table.
+ * <code>Table</code> is used for representing data or components in a pageable
+ * and selectable table.
* </p>
*
* <p>
- * Note! Since version 5, components in Table will not have their caption nor
- * icon rendered. In order to workaround this limitation, wrap your component in
- * a Layout.
+ * Scalability of the Table is largely dictated by the container. A table does
+ * not have a limit for the number of items and is just as fast with hundreds of
+ * thousands of items as with just a few. The current GWT implementation with
+ * scrolling however limits the number of rows to around 500000, depending on
+ * the browser and the pixel height of rows.
+ * </p>
+ *
+ * <p>
+ * Components in a Table will not have their caption nor icon rendered.
* </p>
*
* @author IT Mill Ltd.
@@ -518,6 +524,8 @@ public class Table extends AbstractSelect implements Action.Container,
}
// Assures the visual refresh
+ // FIXME: Is this really needed? Header captions should not affect
+ // content so requestRepaint() should be sufficient.
resetPageBuffer();
refreshRenderedCells();
}
@@ -987,6 +995,8 @@ public class Table extends AbstractSelect implements Action.Container,
columnHeaders.put(propertyId, header);
// Assures the visual refresh
+ // FIXME: Is this really needed? Header captions should not affect
+ // content so requestRepaint() should be sufficient.
refreshRenderedCells();
}
diff --git a/src/com/vaadin/ui/Tree.java b/src/com/vaadin/ui/Tree.java
index 665e98cfee..d28d02216c 100644
--- a/src/com/vaadin/ui/Tree.java
+++ b/src/com/vaadin/ui/Tree.java
@@ -45,6 +45,7 @@ import com.vaadin.terminal.gwt.client.ui.dd.VLazyInitItemIdentifiers;
import com.vaadin.terminal.gwt.client.ui.dd.VOverTreeNode;
import com.vaadin.terminal.gwt.client.ui.dd.VTargetNodeIsChildOf;
import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
+import com.vaadin.tools.ReflectTools;
/**
* Tree component. A Tree can be used to select an item (or multiple items) from
@@ -60,29 +61,12 @@ import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
public class Tree extends AbstractSelect implements Container.Hierarchical,
Action.Container, ItemClickSource, DragSource, DropTarget {
- private static final Method EXPAND_METHOD;
-
- private static final Method COLLAPSE_METHOD;
-
- static {
- try {
- EXPAND_METHOD = ExpandListener.class.getDeclaredMethod(
- "nodeExpand", new Class[] { ExpandEvent.class });
- COLLAPSE_METHOD = CollapseListener.class.getDeclaredMethod(
- "nodeCollapse", new Class[] { CollapseEvent.class });
- } catch (final java.lang.NoSuchMethodException e) {
- // This should never happen
- throw new java.lang.RuntimeException(
- "Internal error finding methods in Tree");
- }
- }
-
/* Private members */
/**
* Set of expanded nodes.
*/
- private final HashSet expanded = new HashSet();
+ private final HashSet<Object> expanded = new HashSet<Object>();
/**
* List of action handlers.
@@ -775,6 +759,9 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
*/
public interface ExpandListener extends Serializable {
+ public static final Method EXPAND_METHOD = ReflectTools.findMethod(
+ ExpandListener.class, "nodeExpand", ExpandEvent.class);
+
/**
* A node has been expanded.
*
@@ -791,7 +778,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
* the Listener to be added.
*/
public void addListener(ExpandListener listener) {
- addListener(ExpandEvent.class, listener, EXPAND_METHOD);
+ addListener(ExpandEvent.class, listener, ExpandListener.EXPAND_METHOD);
}
/**
@@ -801,7 +788,8 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
* the Listener to be removed.
*/
public void removeListener(ExpandListener listener) {
- removeListener(ExpandEvent.class, listener, EXPAND_METHOD);
+ removeListener(ExpandEvent.class, listener,
+ ExpandListener.EXPAND_METHOD);
}
/**
@@ -860,6 +848,9 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
*/
public interface CollapseListener extends Serializable {
+ public static final Method COLLAPSE_METHOD = ReflectTools.findMethod(
+ CollapseListener.class, "nodeCollapse", CollapseEvent.class);
+
/**
* A node has been collapsed.
*
@@ -876,7 +867,8 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
* the Listener to be added.
*/
public void addListener(CollapseListener listener) {
- addListener(CollapseEvent.class, listener, COLLAPSE_METHOD);
+ addListener(CollapseEvent.class, listener,
+ CollapseListener.COLLAPSE_METHOD);
}
/**
@@ -886,7 +878,8 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
* the Listener to be removed.
*/
public void removeListener(CollapseListener listener) {
- removeListener(CollapseEvent.class, listener, COLLAPSE_METHOD);
+ removeListener(CollapseEvent.class, listener,
+ CollapseListener.COLLAPSE_METHOD);
}
/**
@@ -1155,7 +1148,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
Object itemIdOver = getItemIdOver();
if (areChildrenAllowed(itemIdOver)
- && getDropLocation() != VerticalDropLocation.TOP) {
+ && getDropLocation() == VerticalDropLocation.MIDDLE) {
return itemIdOver;
}
return getParent(itemIdOver);
diff --git a/src/com/vaadin/ui/Window.java b/src/com/vaadin/ui/Window.java
index 63daabdf90..f4657d81f6 100644
--- a/src/com/vaadin/ui/Window.java
+++ b/src/com/vaadin/ui/Window.java
@@ -1053,28 +1053,63 @@ public class Window extends Panel implements URIHandler, ParameterHandler {
}
}
+ /**
+ * An interface used for listening to Window close events. Add the
+ * CloseListener to a browser level window or a sub window and
+ * {@link CloseListener#windowClose(CloseEvent)} will be called whenever the
+ * user closes the window.
+ *
+ * <p>
+ * Note that removing windows using {@link #removeWindow(Window)} will not
+ * fire the CloseListener.
+ * </p>
+ */
public interface CloseListener extends Serializable {
+ /**
+ * Called when the user closes a window. Use
+ * {@link CloseEvent#getWindow()} to get a reference to the
+ * {@link Window} that was closed.
+ *
+ * @param e
+ * Event containing
+ */
public void windowClose(CloseEvent e);
}
/**
- * Adds the listener.
+ * Adds a CloseListener to the window.
+ *
+ * For a sub window the CloseListener is fired when the user closes it
+ * (clicks on the close button).
+ *
+ * For a browser level window the CloseListener is fired when the browser
+ * level window is closed. Note that closing a browser level window does not
+ * mean it will be destroyed.
+ *
+ * <p>
+ * Note that removing windows using {@link #removeWindow(Window)} will not
+ * fire the CloseListener.
+ * </p>
*
* @param listener
- * the listener to add.
+ * the CloseListener to add.
*/
public void addListener(CloseListener listener) {
addListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD);
}
/**
- * Removes the listener.
+ * Removes the CloseListener from the window.
+ *
+ * <p>
+ * For more information on CloseListeners see {@link CloseListener}.
+ * </p>
*
* @param listener
- * the listener to remove.
+ * the CloseListener to remove.
*/
public void removeListener(CloseListener listener) {
- addListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD);
+ removeListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD);
}
protected void fireClose() {
diff --git a/src/com/vaadin/ui/themes/BaseTheme.java b/src/com/vaadin/ui/themes/BaseTheme.java
new file mode 100644
index 0000000000..48083f5240
--- /dev/null
+++ b/src/com/vaadin/ui/themes/BaseTheme.java
@@ -0,0 +1,44 @@
+package com.vaadin.ui.themes;
+
+/**
+ * <p>
+ * The Base theme is the foundation for all Vaadin themes. Although it is not
+ * necessary to use it as the starting point for all other themes, it is heavily
+ * encouraged, since it abstracts and hides away many necessary style properties
+ * that the Vaadin terminal expects and needs.
+ * </p>
+ * <p>
+ * When creating your own theme, either extend this class and specify the styles
+ * implemented in your theme here, or extend some other theme that has a class
+ * file specified (e.g. Reindeer or Runo).
+ * </p>
+ * <p>
+ * All theme class files should follow the convention of specifying the theme
+ * name as a string constant <code>THEME_NAME</code>.
+ *
+ * @since 6.3.0
+ *
+ */
+public class BaseTheme {
+
+ public static final String THEME_NAME = "Base";
+
+ /**
+ * Creates a button that looks like a regular hypertext link but still acts
+ * like a normal button.
+ */
+ public static final String BUTTON_LINK = "link";
+
+ /**
+ * Removes extra decorations from the panel.
+ *
+ * @deprecated Base theme does not implement this style, but it is defined
+ * here since it has been a part of the framework before
+ * multiple themes were available. Use the constant provided by
+ * the theme you're using instead, e.g.
+ * {@link Reindeer#PANEL_LIGHT} or {@link Runo#PANEL_LIGHT}.
+ */
+ @Deprecated
+ public static final String PANEL_LIGHT = "light";
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/ui/themes/Reindeer.java b/src/com/vaadin/ui/themes/Reindeer.java
new file mode 100644
index 0000000000..acbf003151
--- /dev/null
+++ b/src/com/vaadin/ui/themes/Reindeer.java
@@ -0,0 +1,163 @@
+package com.vaadin.ui.themes;
+
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.FormLayout;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.VerticalLayout;
+
+public class Reindeer extends BaseTheme {
+
+ public static final String THEME_NAME = "Reindeer";
+
+ /***************************************************************************
+ *
+ * Label styles
+ *
+ **************************************************************************/
+
+ /**
+ * Large font for main application headings
+ */
+ public static final String LABEL_H1 = "h1";
+
+ /**
+ * Large font for different sections in the application
+ */
+ public static final String LABEL_H2 = "h2";
+
+ /**
+ * Small and a little lighter font
+ */
+ public static final String LABEL_SMALL = "light";
+
+ /***************************************************************************
+ *
+ * Button styles
+ *
+ **************************************************************************/
+
+ /**
+ * Default action style for buttons (the button that gets activated when
+ * user presses 'enter' in a form). Use sparingly, only one default button
+ * per screen should be visible.
+ */
+ public static final String BUTTON_DEFAULT = "primary";
+
+ /**
+ * Small sized button, use for context specific actions for example
+ */
+ public static final String BUTTON_SMALL = "small";
+
+ /***************************************************************************
+ *
+ * TextField styles
+ *
+ **************************************************************************/
+
+ /**
+ * Small sized text field with small font
+ */
+ public static final String TEXTFIELD_SMALL = "small";
+
+ /***************************************************************************
+ *
+ * Panel styles
+ *
+ **************************************************************************/
+
+ /**
+ * Removes borders and background color from the panel
+ */
+ public static final String PANEL_LIGHT = "light";
+
+ /***************************************************************************
+ *
+ * SplitPanel styles
+ *
+ **************************************************************************/
+
+ /**
+ * Reduces the split handle to a minimal size (1 pixel)
+ */
+ public static final String SPLITPANEL_SMALL = "small";
+
+ /***************************************************************************
+ *
+ * TabSheet styles
+ *
+ **************************************************************************/
+
+ /**
+ * Removes borders and background color from the tab sheet, and shows the
+ * tabs as a small bar.
+ */
+ public static final String TABSHEET_BAR = "bar";
+
+ /**
+ * Removes borders and background color from the tab sheet. The tabs are
+ * presented with minimal lines indicating the selected tab.
+ */
+ public static final String TABSHEET_MINIMAL = "minimal";
+
+ /***************************************************************************
+ *
+ * Table styles
+ *
+ **************************************************************************/
+
+ /**
+ * Removes borders from the table
+ */
+ public static final String TABLE_BORDERLESS = "borderless";
+
+ /**
+ * Makes the table headers dark and more prominent.
+ */
+ public static final String TABLE_STRONG = "strong";
+
+ /***************************************************************************
+ *
+ * Layout styles
+ *
+ **************************************************************************/
+
+ /**
+ * Changes the background of a layout to a shade of blue. Applies to
+ * {@link VerticalLayout}, {@link HorizontalLayout}, {@link GridLayout},
+ * {@link FormLayout} and {@link CssLayout}.
+ */
+ public static final String LAYOUT_BLUE = "blue";
+
+ /**
+ * <p>
+ * Changes the background of a layout to almost black, and at the same time
+ * transforms contained components to their black style correspondents when
+ * available. At least texts, buttons, text fields, selects, date fields,
+ * tables and a few other component styles should change.
+ * </p>
+ * <p>
+ * Applies to {@link VerticalLayout}, {@link HorizontalLayout},
+ * {@link GridLayout}, {@link FormLayout} and {@link CssLayout}.
+ * </p>
+ *
+ */
+ public static final String LAYOUT_BLACK = "black";
+
+ /***************************************************************************
+ *
+ * Window styles
+ *
+ **************************************************************************/
+
+ /**
+ * Makes the whole window white and increases the font size of the title.
+ */
+ public static final String WINDOW_LIGHT = "light";
+
+ /**
+ * Makes the whole window black, and changes contained components in the
+ * same way as {@link #LAYOUT_BLACK} does.
+ */
+ public static final String WINDOW_BLACK = "black";
+}
diff --git a/src/com/vaadin/ui/themes/Runo.java b/src/com/vaadin/ui/themes/Runo.java
new file mode 100644
index 0000000000..4df6046756
--- /dev/null
+++ b/src/com/vaadin/ui/themes/Runo.java
@@ -0,0 +1,30 @@
+package com.vaadin.ui.themes;
+
+
+public class Runo extends BaseTheme {
+
+ public static final String THEME_NAME = "Runo";
+
+ /***************************************************************************
+ *
+ * Button styles
+ *
+ **************************************************************************/
+
+ /**
+ * Small sized button, use for context specific actions for example
+ */
+ public static final String BUTTON_SMALL = "small";
+
+ /***************************************************************************
+ *
+ * Panel styles
+ *
+ **************************************************************************/
+
+ /**
+ * Removes borders and background color from the panel
+ */
+ public static final String PANEL_LIGHT = "light";
+
+}