aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/vaadin/ui/DefaultRoot.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/vaadin/ui/DefaultRoot.java')
-rw-r--r--src/com/vaadin/ui/DefaultRoot.java146
1 files changed, 143 insertions, 3 deletions
diff --git a/src/com/vaadin/ui/DefaultRoot.java b/src/com/vaadin/ui/DefaultRoot.java
index 1bc4e7631f..a04d1baf08 100644
--- a/src/com/vaadin/ui/DefaultRoot.java
+++ b/src/com/vaadin/ui/DefaultRoot.java
@@ -1,22 +1,29 @@
package com.vaadin.ui;
+import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import com.vaadin.Application;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Terminal;
import com.vaadin.terminal.gwt.client.ui.VView;
+import com.vaadin.ui.Window.CloseListener;
@ClientWidget(VView.class)
public class DefaultRoot extends AbstractComponentContainer implements Root {
private final Component content;
private Terminal terminal;
- private final Application application;
+ private Application application;
- public DefaultRoot(Application application, Component content) {
- this.application = application;
+ /**
+ * List of windows in this root.
+ */
+ private final LinkedHashSet<Window> windows = new LinkedHashSet<Window>();
+
+ public DefaultRoot(Component content) {
this.content = content;
addComponent(content);
}
@@ -38,6 +45,22 @@ public class DefaultRoot extends AbstractComponentContainer implements Root {
@Override
public void paintContent(PaintTarget target) throws PaintException {
content.paint(target);
+
+ // Paint subwindows
+ for (final Iterator<Window> i = windows.iterator(); i.hasNext();) {
+ final Window w = i.next();
+ w.paint(target);
+ }
+
+ if (pendingFocus != null) {
+ // ensure focused component is still attached to this main window
+ if (pendingFocus.getRoot() == this
+ || (pendingFocus.getRoot() != null && pendingFocus
+ .getRoot().getParent() == this)) {
+ target.addAttribute("focused", pendingFocus);
+ }
+ pendingFocus = null;
+ }
}
public Iterator<Component> getComponentIterator() {
@@ -55,4 +78,121 @@ public class DefaultRoot extends AbstractComponentContainer implements Root {
public void setTerminal(Terminal terminal) {
this.terminal = terminal;
}
+
+ public void setApplication(Application application) {
+ if (application == null) {
+ throw new NullPointerException("application");
+ } else if (this.application != null) {
+ throw new IllegalStateException("Application has already been set");
+ } else {
+ this.application = application;
+ }
+ }
+
+ /**
+ * Adds a window inside this root.
+ *
+ * <p>
+ * Adding windows inside another window creates "subwindows". These windows
+ * should not be added to application directly and are not accessible
+ * directly with any url. Addding windows implicitly sets their parents.
+ * </p>
+ *
+ * <p>
+ * Only one level of subwindows are supported. Thus you can add windows
+ * inside such windows whose parent is <code>null</code>.
+ * </p>
+ *
+ * @param window
+ * @throws IllegalArgumentException
+ * if a window is added inside non-application level window.
+ * @throws NullPointerException
+ * if the given <code>Window</code> is <code>null</code>.
+ */
+ public void addWindow(Window window) throws IllegalArgumentException,
+ NullPointerException {
+
+ if (window == null) {
+ throw new NullPointerException("Argument must not be null");
+ }
+
+ if (window.getApplication() != null) {
+ throw new IllegalArgumentException(
+ "Window is already attached to an application.");
+ }
+
+ attachWindow(window);
+ }
+
+ private void attachWindow(Window w) {
+ windows.add(w);
+ w.setParent(this);
+ requestRepaint();
+ }
+
+ /**
+ * Remove the given subwindow from this root.
+ *
+ * Since Vaadin 6.5, {@link CloseListener}s are called also when explicitly
+ * removing a window by calling this method.
+ *
+ * Since Vaadin 6.5, returns a boolean indicating if the window was removed
+ * or not.
+ *
+ * @param window
+ * Window to be removed.
+ * @return true if the subwindow was removed, false otherwise
+ */
+ public boolean removeWindow(Window window) {
+ if (!windows.remove(window)) {
+ // Window window is not a subwindow of this root.
+ return false;
+ }
+ window.setParent(null);
+ window.fireClose();
+ requestRepaint();
+
+ return true;
+ }
+
+ public Collection<Window> getWindows() {
+ return Collections.unmodifiableCollection(windows);
+ }
+
+ public int getTabIndex() {
+ throw new IllegalStateException("Tab index not defined for roots");
+ }
+
+ public void setTabIndex(int tabIndex) {
+ throw new IllegalStateException("Tab index not defined for roots");
+ }
+
+ @Override
+ public void focus() {
+ super.focus();
+ }
+
+ /**
+ * Component that should be focused after the next repaint. Null if no focus
+ * change should take place.
+ */
+ private Focusable pendingFocus;
+
+ /**
+ * This method is used by Component.Focusable objects to request focus to
+ * themselves. Focus renders must be handled at window level (instead of
+ * Component.Focusable) due we want the last focused component to be focused
+ * in client too. Not the one that is rendered last (the case we'd get if
+ * implemented in Focusable only).
+ *
+ * To focus component from Vaadin application, use Focusable.focus(). See
+ * {@link Focusable}.
+ *
+ * @param focusable
+ * to be focused on next paint
+ */
+ public void setFocusedComponent(Focusable focusable) {
+ pendingFocus = focusable;
+ requestRepaint();
+ }
}