IT Mill Toolkit Release 5 introduces support for multiple application-level
windows that can be used just like the main window. All such windows use the
same application session. Each window is identified with a URL that is used to
access it. This makes it possible to bookmark application-level windows. Such
windows can even be created dynamically based on URLs.
Application-level windows allow several uses important for usability of
browser-based applications.
Creating New Application-Level Windows
Creating a new application-level window is much like creating a child
window, except that the window is added with
addWindow() to the application object instead of
the main window.
public class WindowTestApplication extends Application {
public void init() {
final Window main = new Window ("Window Test Application");
setMainWindow(main);
/* Create a new window. */
final Window mywindow = new Window("Second Window");
/* Manually set the name of the window. */
mywindow.setName("mywindow");
/* Add some content to the window. */
mywindow.addComponent(new Label("This is a second window."));
/* Add the window to the application. */
addWindow(mywindow);
}
}
This creates the window object that a user can view by opening the URL in
a browser. Creating a application-level window object does not open a new
browser window automatically to view the object, but if you wish to open
one, you have to do it explicitly as shown below. An application-level
window has a unique URL, which is based on the application URL and the
name of the window given with the setName()
method. For example, if the application URL is
http://localhost:8080/myapp/ and the window name is
mywindow, the URL for the window will be
http://localhost:8080/myapp/mywindow/. If the name of a window
is not explicitly set with setName(), an
automatically generated name will be used. The name can be retrieved with
the getName() method and the entire URL with
getURL().
There are three typical ways to open a new window: using the
open() method of Window
class, a Link, or referencing it from HTML or
JavaScript code written inside a Label component.
The Window open() method
takes a resource to open and the target. You can use
ExternalResource to open a specific URL, which you
get from the window to be opened with the
getURL() method.
/* Create a button to open a new window. */
main.addComponent(new Button("Click to open new window",
new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
// Open the window.
main.open(new ExternalResource(mywindow.getURL()), "_new");
}
}));
The target name is one of the HTML target names. How the window is
exactly opened depends on the browser. Browsers that support tabbed
browsing can open the window in another tab, depending on the browser
settings.
Another typical way to open windows is to use a Link
component with the window URL as an
ExternalResource.
/* Add a link to the second window. */
Link link = new Link("Click to open second window",
new ExternalResource(mywindow.getURL()));
link.setTargetName("second");
link.setTargetHeight(300);
link.setTargetWidth(300);
link.setTargetBorder(Link.TARGET_BORDER_DEFAULT);
main.addComponent(link);
Using a Link allows you to specify parameters for
the window that opens by clicking on the link. Above, we set the
dimensions of the window and specify what window controls the window
should contain. The Link.TARGET_BORDER_DEFAULT
specifies to use the default, which includes most of the usual window
controls, such as the menu, toolbar, and status bar.
Another way to allow the user to open a window is to insert the URL in
HTML code inside a Label. This allows even more
flexibility in specifying how the window should be opened.
/* Add the link manually inside a Label. */
main.addComponent(new Label("Second window: <a href='"
+ mywindow.getURL() + "' target='second'>click to open</a>",
Label.CONTENT_XHTML));
main.addComponent(new Label("The second window can be accessed through URL: "
+ mywindow.getURL()));
-- This section is unfinished --
Caveats in Using Multiple Windows
Additional windows have the same problem as a single window: closing a
window does not cause an event. If a user clicks on a close button of
a window, the browser usually just closes it without running any
JavaScript handlers for such an event. Therefore, the server will not
know that the user closed the window and the server-side object will
be left hanging.
If the window has a manually set URI, the user can reconnect to it
using the URI.
Communication Between Windows
For cases where you need communication between windows, we recommend
using floating child windows. In IT Mill Toolkit Release 5, an
application window can not update the data in other windows. The
contents of a window can only updated when the particular window makes
a request to the server. The request can be caused by user input or
through polling.
Changing the server-side state of a window while processing user event
from another window can potentially cause serious problems. Changing
the client-side state of a window does not always immediately
communicate the changes to server. The server-side state can therefore
be out of sync with the client-side state.
The following example creates a second window that changes the
contents of the main window, as illustrated in the figure above. In
this simple case, changing the main window contents is safe.
// Create a table in the main window to hold items added in the second window
final Table table = new Table();
table.setPageLength(5);
table.getSize().setWidth(100, Size.UNITS_PERCENTAGE);
table.addContainerProperty("Name", String.class, "");
main.addComponent(table);
// Create the second window
final Window adderWindow = new Window("Add Items");
adderWindow.setName("win-adder");
main.getApplication().addWindow(adderWindow);
// Create selection component to add items to the table
final NativeSelect select = new NativeSelect("Select item to add");
select.setImmediate(true);
adderWindow.addComponent(select);
// Add some items to the selection
String items[] = new String[]{"-- Select --", "Mercury", "Venus",
"Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"};
for (int i=0; i<items.length; i++)
select.addItem(items[i]);
select.setNullSelectionItemId(items[0]);
// When an item is selected in the second window, add
// table in the main window
select.addListener(new ValueChangeListener() {
public void valueChange(ValueChangeEvent event) {
// If the selected value is something else but null selection item.
if (select.getValue() != null) {
// Add the selected item to the table in the main window
table.addItem(new Object[]{select.getValue()}, new Integer(table.size()));
}
}
});
// Link to open the selection window
Link link = new Link("Click to open second window",
new ExternalResource(adderWindow.getURL()),
"_new", 50, 200, Link.TARGET_BORDER_DEFAULT);
main.addComponent(link);
// Enable polling to update the main window
ProgressIndicator poller = new ProgressIndicator();
poller.addStyleName("invisible");
main.addComponent(poller);
The example uses an invisible ProgressIndicator
to implement polling. This is sort of a trick and a more proper API
for polling is under design. Making the progress indicator invisible
requires the following CSS style definition:
.i-progressindicator-invisible {
display: none;
}