Important Notice - Forums is archived
To simplify things and help our users to be more productive, we have archived the current forum and focus our efforts on helping developers on Stack Overflow. You can post new questions on Stack Overflow or join our Discord channel.

Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.
multiple tabs, firefox causes spurious close events
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:-
1) Deploy this application
2) Open firefox (3.6.10) connection to it
3) Open a second tab from same browser
4) 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;
}
}
}