/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.servoy.j2db.IBasicFormManager.History;
import com.servoy.j2db.plugins.IPlugin;
import com.servoy.j2db.scripting.JSWindow;
import com.servoy.j2db.scripting.RuntimeWindow;
import com.servoy.j2db.util.Utils;
/**
* An abstract manager of JSWindows. Creates windows, keeps track of current window and windows that are in use.
* It is meant to be extended for each type of user interface.
* @author acostescu
* @since 6.0
*/
public abstract class RuntimeWindowManager
{
private static final String MAIN_APPLICATION_WINDOW_NAME = "mainApplicationWindow";
protected final HashMap<String, RuntimeWindow> windows = new HashMap<String, RuntimeWindow>();
private String currentWindowName = null; // this should be null when the main application window is the current window
protected IApplication application;
public RuntimeWindowManager(IApplication application)
{
this.application = application;
windows.put(MAIN_APPLICATION_WINDOW_NAME, getMainApplicationWindow());
}
protected abstract RuntimeWindow getMainApplicationWindow();
protected abstract RuntimeWindow createWindowInternal(String windowName, int type, RuntimeWindow parent);
/**
* @param string the name of the window. If this is null, returns a wrapper for the main application frame.
* @return the user window with the specified name or a wrapper for the main application frame. if name is null.
*/
public RuntimeWindow getWindow(String windowName)
{
if (windowName == null) windowName = MAIN_APPLICATION_WINDOW_NAME;
return windows.get(windowName);
}
/**
* Create a new user window. If a window with this name already exists, it will be closed/destroyed first.
* @param windowName the name of the window. Must not be null.
* @param parent
* @param i
* @return the newly created window.
*/
public RuntimeWindow createWindow(String windowName, int type, JSWindow parent)
{
RuntimeWindow win = windows.get(windowName);
if (win != null)
{
win.destroy();
}
// RuntimeWindow currentWindow = null;
// if (type == JSWindow.DIALOG || type == JSWindow.MODAL_DIALOG)
// {
// RuntimeWindow pw = application.getRuntimeWindowManager().getCurrentWindow();
// if (pw != null)
// {
// currentWindow = pw.getJSWindow().getImpl();
// }
// }
win = createWindowInternal(windowName, type, parent != null ? parent.getImpl() : null); // was : currentWindow, but why use fixed parent if it was not specified in JS? better decide each time the window/dialog is shown, so null should be better
if (win != null) windows.put(windowName, win);
return win;
}
public void removeWindow(String windowName)
{
windows.remove(windowName);
}
/**
* Get the name of the current user window/dialog (null for the main window).
*/
public String getCurrentWindowName()
{
return currentWindowName;
}
/**
* Set the name of the current user window/dialog (null for the main window).
*/
public void setCurrentWindowName(String currentWindowName)
{
String oldName = this.currentWindowName;
this.currentWindowName = currentWindowName;
J2DBGlobals.firePropertyChange(application, IPlugin.PROPERTY_CURRENT_WINDOW, oldName, currentWindowName);
}
public RuntimeWindow getCurrentWindow()
{
RuntimeWindow window = getWindow(currentWindowName);
if (window == null && currentWindowName != null)
{
// the current window shouldn't be null, this could be a new tab in the web, create it
window = createWindowInternal(currentWindowName, JSWindow.WINDOW, null);
windows.put(currentWindowName, window);
}
return window;
}
/**
* Returns a list of window names that represents the order in which these windows should be closed so as to avoid unexpected results.<br>
* When windows sit on top of other windows, the top-most windows should probably be closed first. (for example if you have many modal windows on top of each-other and
* you need to close all the windows, you might want to keep closing the top-most window until all are closed)
*/
protected abstract List<String> getOrderedContainers();
protected boolean doCloseFormInWindow(IBasicMainContainer container)
{
boolean ok = true;
IFormController fp = container.getController();
if (fp != null)
{
List<Runnable> invokeLaterRunnables = new ArrayList<Runnable>();
ok = fp.notifyVisible(false, invokeLaterRunnables);
Utils.invokeLater(application, invokeLaterRunnables);
IApplication app = fp.getApplication();
if (app.getFormManager() != null)
{
int form_id = fp.getForm().getNavigatorID();
if (form_id > 0)
{
IFormController navigator = (IFormController)app.getFormManager().getForm(app.getFlattenedSolution().getForm(form_id).getName()).getFormUI().getController();
List<Runnable> invokeLaterRunnables2 = new ArrayList<Runnable>();
if (navigator != null) navigator.notifyVisible(false, invokeLaterRunnables2);
}
}
}
if (ok)
{
hideContainer(container);
}
return ok;
}
/**
* @param container
*/
protected void hideContainer(IBasicMainContainer container)
{
RuntimeWindow w = getWindow(container.getContainerName());
if (w != null) w.hideUI();
}
public boolean closeFormInWindow(String windowName, boolean closeAll)
{
IBasicFormManager fm = application.getFormManager();
IBasicMainContainer container = null;
if ((windowName == null || windowName.replace(" ", "").length() == 0) && closeAll == true) //$NON-NLS-1$ //$NON-NLS-2$
{
boolean result = true;
List<String> oc = getOrderedContainers();
boolean ret = true;
for (String key : oc)
{
if (key != null)
{
IBasicMainContainer mContainer = fm.getMainContainer(key);
if (fm.getMainContainer(null) != mContainer && mContainer != null)
{
ret = doCloseFormInWindow(mContainer);
if (ret)
{
// If dialog is closed then we must clear the complete history
History hist = fm.getHistory(mContainer);
hist.clear();
}
}
result = result && ret;
}
}
return result;
}
else if (windowName == null || windowName.replace(" ", "").length() == 0) //$NON-NLS-1$ //$NON-NLS-2$
{
container = fm.getCurrentContainer();
}
else
{
container = fm.getMainContainer(windowName);
}
if (container != null)
{
//don't do anything if it is the main container
if (container == fm.getMainContainer(null)) return false;
if (!closeAll)
{
// legacy V3 behavior, when multiple forms are shown in same form, go back 1 in history
History hist = fm.getHistory(container);
if (hist.getLength() > 1 && hist.getIndex() > 0)
{
storeWindowBounds(container);
boolean b = hist.removeIndex(hist.getIndex());
if (b)
{
restoreWindowBounds(container);
}
return b;
}
}
boolean ret = doCloseFormInWindow(container);
if (ret)
{
// If dialog is closed then we must clear the complete history
History hist = fm.getHistory(container);
hist.clear();
}
return ret;
}
return true;
}
protected boolean restoreWindowBounds(IBasicMainContainer container)
{
// dummy; subclasses can override if needed
return false;
}
protected void storeWindowBounds(IBasicMainContainer container)
{
// dummy; subclasses can override if needed
}
public Object getCurrentWindowWrappedObject()
{
RuntimeWindow w = getCurrentWindow();
return w != null ? w.getWrappedObject() : null;
}
public Object getWindowWrappedObject(String windowName)
{
RuntimeWindow w = getWindow(windowName);
return w != null ? w.getWrappedObject() : null;
}
}