/*
* Copyright 2009-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package griffon.javafx;
import griffon.core.GriffonApplication;
import griffon.util.ConfigUtils;
import griffon.util.GriffonNameUtils;
import griffon.util.RunnableWithArgs;
import groovy.lang.Closure;
import javafx.stage.Window;
import java.util.Collections;
import java.util.Map;
/**
* Implementation of a per window {@code WindowDisplayHandler} that can be configured via a DSL.
* <p/>
* This is the default {@code WindowDisplayHandler} used by {@code javafxApplication}. It expects a configuration entry in
* <code>griffon-app/conf/Config.groovy</code> that looks like the following one
* <p/>
* <p/>
* <pre>
* javafx {
* windowManager {
* myWindowName = [
* show: {window, app -> ... },
* hide: {window, app -> ... }
* ]
* myOtherWindowName = [
* show: {window, app -> ... }
* ]
* }
* }
* </pre>
* <p/>
* For these settings to work you must specify a <code>name:</code> property on the Window/Frame instance. This {@code WindowDisplayHandler}
* is smart enough to use the default show/hide behavior should any or both are not specified or if a window name does not have a matching
* configuration. The default behavior will also be used if the Window/Frame does not have a value for its <code>name:</code> property.
* <p/>
* There's a third option that can be set for each configured window, and that is a delegate {@code WindowDisplayHandler} that will be used
* for that window alone. The following example shows how it can be configured
* <p/>
* <p/>
* <pre>
* javafx {
* windowManager {
* myWindowName = [
* handler: new MyCustomWindowDisplayHandler()
* ]
* myOtherWindowName = [
* show: {window, app -> ... }
* ]
* }
* }
* </pre>
* <p/>
* Lastly, a global handler can be specified for all windows that have not been configured. If specified, this handler will override the
* usage of the default one. It can be configured as follows
* <p/>
* <p/>
* <pre>
* javafx {
* windowManager {
* defaultHandler = new MyCustomWindowDisplayHandler()
* myOtherWindowName = [
* show: {window, app -> ... }
* ]
* }
* }
* </pre>
* <p/>
* Fine grained control for default <code>show</code> and <code>hide</code> is also possible, by specifying <code>defaultShow</code> and/or
* <code>defaultHide</code> properties at the global level. These properties take precedence over <code>defaultHandler</code> .
* <p/>
* <p/>
* <pre>
* javafx {
* windowManager {
* defaultHide = {window, app -> ... }
* myOtherWindowName = [
* show: {window, app -> ... }
* ]
* }
* }
* </pre>
* <p/>
* <strong>Note:</strong> the value for <code>show</code> and <code>hide</code> can be either a Closure or a {@code RunnableWithArgs}.
*
* @author Andres Almiray
*/
public class ConfigurableWindowDisplayHandler implements WindowDisplayHandler {
private static final WindowDisplayHandler DEFAULT_WINDOW_DISPLAY_HANDLER = new DefaultWindowDisplayHandler();
public void show(Window window, JavaFXGriffonApplication application) {
WindowManager windowManager = application.getWindowManager();
String name = windowManager.findWindowName(window);
if (!GriffonNameUtils.isBlank(name)) {
Map<String, Object> options = windowBlock(application, name);
if (!options.isEmpty()) {
Object handler = options.get("show");
if (canBeRun(handler)) {
run(handler, window, application);
return;
} else if (options.get("handler") instanceof WindowDisplayHandler) {
((WindowDisplayHandler) options.get("handler")).show(window, application);
return;
}
}
}
Map<String, Object> options = windowManagerBlock(application);
if (!options.isEmpty()) {
Object handler = options.get("defaultShow");
if (canBeRun(handler)) {
run(handler, window, application);
return;
}
}
fetchDefaultWindowDisplayHandler(application).show(window, application);
}
public void hide(Window window, JavaFXGriffonApplication application) {
WindowManager windowManager = application.getWindowManager();
String name = windowManager.findWindowName(window);
if (!GriffonNameUtils.isBlank(name)) {
Map<String, Object> options = windowBlock(application, name);
if (!options.isEmpty()) {
Object handler = options.get("hide");
if (canBeRun(handler)) {
run(handler, window, application);
return;
} else if (options.get("handler") instanceof WindowDisplayHandler) {
((WindowDisplayHandler) options.get("handler")).hide(window, application);
return;
}
}
}
Map<String, Object> options = windowManagerBlock(application);
if (!options.isEmpty()) {
Object handler = options.get("defaultHide");
if (canBeRun(handler)) {
run(handler, window, application);
return;
}
}
fetchDefaultWindowDisplayHandler(application).hide(window, application);
}
private boolean canBeRun(Object obj) {
return obj instanceof Closure || obj instanceof RunnableWithArgs;
}
@SuppressWarnings("rawtypes")
private void run(Object obj, Window window, GriffonApplication application) {
if (obj instanceof Closure) {
((Closure) obj).call(window, application);
} else {
((RunnableWithArgs) obj).run(new Object[]{window, application});
}
}
@SuppressWarnings("unchecked")
private Map<String, Object> windowManagerBlock(GriffonApplication application) {
Map<String, Object> block = (Map<String, Object>) ConfigUtils.getConfigValue(application.getConfig(), "javafx.windowManager");
return block != null ? block : Collections.<String, Object>emptyMap();
}
@SuppressWarnings("unchecked")
private Map<String, Object> windowBlock(GriffonApplication application, String windowName) {
Map<String, Object> options = windowManagerBlock(application);
Map<String, Object> block = (Map<String, Object>) options.get(windowName);
return block != null ? block : Collections.<String, Object>emptyMap();
}
private WindowDisplayHandler fetchDefaultWindowDisplayHandler(GriffonApplication application) {
Object handler = windowManagerBlock(application).get("defaultHandler");
return handler instanceof WindowDisplayHandler ? (WindowDisplayHandler) handler : DEFAULT_WINDOW_DISPLAY_HANDLER;
}
}