Multiple tabs are a curse…
I’ve followed the recommended recipe at https://vaadin.com/web/joonas/wiki/-/wiki/Main/Supporting%20Multible%20Tabs, and taken the source code from the MultiTabCalc example therein. When I connect from firefox, it works OK, but I see a spurious close event when I open the second tab. In our real app, that is causing some issues.
Step-by-step:-
- Deploy this application
- Open firefox (3.6.10) connection to it
- Open a second tab from same browser
- Check the logs - we receive a close event for second tab even though I haven’t closed either tab.
Here’s the code (mostly from above recipe):-
package com.example.calc;
import java.util.logging.Logger;
import com.vaadin.Application;
import com.vaadin.terminal.ExternalResource;
import com.vaadin.ui.*;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
@SuppressWarnings("serial")
public class CalcApplication extends Application {
private static final Logger logger = Logger.getLogger(CalcApplication.class.getName());
@Override
public void init() {
// The first window is the main
final Window w = new CalcWindow();
logger.warning("*** init: app:" + this + ", mainWindow:" + w + ", name: " + w.getName());
setMainWindow(w);
// Building the window is separated from the application initialization
}
// Overriding getWindow(String) is required to get multiple browser
// windows/tabs to work
@Override
public Window getWindow(String name) {
// If the window is identified by name, we are good to go
Window w = super.getWindow(name);
// If not, we must create a new window for this new browser window/tab
if (w == null) {
w = new CalcWindow();
logger.warning("*** new window:" + w + ", name:" + name);
// Use the random name given by the framework to identify this
// window in future
w.setName(name);
addWindow(w);
// Move to the url to remember the name in the future
w.open(new ExternalResource(w.getURL()));
}
return w;
}
// Per window state and layout initialization is moved from the Application
// to Window
private class CalcWindow extends Window implements ClickListener {
private double current = 0.0;
private double stored = 0.0;
private char lastOperationRequested = 'C';
private final Label display = new Label("0.0");
final GridLayout layout = new GridLayout(4, 5);
CalcWindow() {
setCaption("Calculator Application");
setContent(layout);
layout.addComponent(display, 0, 0, 3, 0);
String[] operations = new String[]
{ "7", "8", "9", "/", "4", "5",
"6", "*", "1", "2", "3", "-", "0", "=", "C", "+" };
for (String caption : operations) {
Button button = new Button(caption);
button.addListener(this);
layout.addComponent(button);
}
addListener(new CloseListener() {
@Override
public void windowClose(CloseEvent e) {
logger.warning("Close event sent to " + getName());
}
});
}
public void buttonClick(ClickEvent event) {
Button button = event.getButton();
logger.warning("*** buttonClick: app:" + button.getApplication() + ", mw:" + button.getApplication().getMainWindow()
+ ", window: " + this);
char requestedOperation = button.getCaption().charAt(0);
double newValue = calculate(requestedOperation);
display.setValue(newValue);
}
private double calculate(char requestedOperation) {
if ('0' <= requestedOperation && requestedOperation <= '9') {
current = current * 10
+ Double.parseDouble("" + requestedOperation);
return current;
}
switch (lastOperationRequested) {
case '+':
stored += current;
break;
case '-':
stored -= current;
break;
case '/':
stored /= current;
break;
case '*':
stored *= current;
break;
case 'C':
stored = current;
break;
}
lastOperationRequested = requestedOperation;
current = 0.0;
if (requestedOperation == 'C') {
stored = 0.0;
}
return stored;
}
}
}