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;
		}
	}

}