| 
001 /*002  * Copyright 2008-2017 the original author or authors.
 003  *
 004  * Licensed under the Apache License, Version 2.0 (the "License");
 005  * you may not use this file except in compliance with the License.
 006  * You may obtain a copy of the License at
 007  *
 008  *     http://www.apache.org/licenses/LICENSE-2.0
 009  *
 010  * Unless required by applicable law or agreed to in writing, software
 011  * distributed under the License is distributed on an "AS IS" BASIS,
 012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 013  * See the License for the specific language governing permissions and
 014  * limitations under the License.
 015  */
 016 package org.codehaus.griffon.runtime.core.view;
 017
 018 import griffon.core.CallableWithArgs;
 019 import griffon.core.GriffonApplication;
 020 import griffon.core.RunnableWithArgs;
 021 import griffon.core.view.WindowDisplayHandler;
 022 import griffon.exceptions.InstanceNotFoundException;
 023 import org.slf4j.Logger;
 024 import org.slf4j.LoggerFactory;
 025
 026 import javax.annotation.Nonnull;
 027 import javax.annotation.Nullable;
 028 import javax.inject.Inject;
 029 import javax.inject.Named;
 030 import java.util.Collections;
 031 import java.util.Map;
 032
 033 import static griffon.util.AnnotationUtils.named;
 034 import static griffon.util.ConfigUtils.getConfigValue;
 035 import static griffon.util.GriffonNameUtils.requireNonBlank;
 036 import static java.util.Objects.requireNonNull;
 037
 038 /**
 039  * Implementation of a per window {@code WindowDisplayHandler} that can be configured via a DSL.<p>
 040  * This is the default {@code WindowDisplayHandler} used by {@code SwingApplication}. It expects a configuration
 041  * entry in <code>griffon-app/conf/Config.groovy</code> that looks like the following one<p>
 042  * <pre>
 043  *     windowManager {
 044  *         myWindowName = [
 045  *             show: {name, window -> ... },
 046  *             hide: {name, window -> ... }
 047  *         ]
 048  *         myOtherWindowName = [
 049  *             show: {name, window -> ... }
 050  *         ]
 051  *     }
 052  * </pre>
 053  * <p>
 054  * For these settings to work you must specify a <code>name:</code> property on the Window/Frame instance. This
 055  * {@code WindowDisplayHandler} is smart enough to use the default show/hide behavior should any or both are not specified
 056  * or if a window name does not have a matching configuration. The default behavior will also be used if the Window/Frame
 057  * does not have a value for its <code>name:</code> property.<p>
 058  * There's a third option that can be set for each configured window, and that is a delegate {@code WindowDisplayHandler} that
 059  * will be used for that window alone. The following example shows how it can be configured<p>
 060  * <pre>
 061  *     windowManager {
 062  *         myWindowName = [
 063  *             handler: new MyCustomWindowDisplayHandler()
 064  *         ]
 065  *         myOtherWindowName = [
 066  *             show: {name, window -> ... }
 067  *         ]
 068  *     }
 069  * </pre>
 070  * <p>
 071  * Lastly, a global handler can be specified for all windows that have not been configured. If specified, this handler will
 072  * override the usage of the default one. It can be configured as follows<p>
 073  * <pre>
 074  *     windowManager {
 075  *         defaultHandler = new MyCustomWindowDisplayHandler()
 076  *         myOtherWindowName = [
 077  *             show: {name, window -> ... }
 078  *         ]
 079  *     }
 080  * </pre>
 081  * <p>
 082  * Fine grained control for default <code>show</code> and <code>hide</code> is also possible, by specifying <code>defaultShow</code>
 083  * and/or <code>defaultHide</code> properties at the global level. These properties take precedence over <code>defaultHandler</code> .
 084  * <p>
 085  * <pre>
 086  *     windowManager {
 087  *         defaultHide = {name, window -> ... }
 088  *         myOtherWindowName = [
 089  *             show: {name, window -> ... }
 090  *         ]
 091  *     }
 092  * </pre>
 093  * <p>
 094  * <strong>Note:</strong> the value for <code>show</code> and <code>hide</code> can be either a Closure or a {@code RunnableWithArgs}.
 095  *
 096  * @author Andres Almiray
 097  * @since 2.0.0
 098  */
 099 public class ConfigurableWindowDisplayHandler<W> implements WindowDisplayHandler<W> {
 100     protected static final String ERROR_NAME_BLANK = "Argument 'name' must not be blank";
 101     protected static final String ERROR_WINDOW_NULL = "Argument 'window' must not be null";
 102     private static final Logger LOG = LoggerFactory.getLogger(ConfigurableWindowDisplayHandler.class);
 103     private static final String HANDLER = "handler";
 104     private final GriffonApplication application;
 105     private final WindowDisplayHandler<W> delegateWindowsDisplayHandler;
 106
 107     @Inject
 108     public ConfigurableWindowDisplayHandler(@Nonnull GriffonApplication application, @Nonnull @Named("defaultWindowDisplayHandler") WindowDisplayHandler<W> delegateWindowsDisplayHandler) {
 109         this.application = requireNonNull(application, "Argument 'application' must not be null");
 110         this.delegateWindowsDisplayHandler = requireNonNull(delegateWindowsDisplayHandler, "Argument 'delegateWindowsDisplayHandler' must not be null");
 111     }
 112
 113     @SuppressWarnings("unchecked")
 114     public void show(@Nonnull String name, @Nonnull W window) {
 115         requireNonBlank(name, ERROR_NAME_BLANK);
 116         requireNonNull(window, ERROR_WINDOW_NULL);
 117
 118         Map<String, Object> options = windowBlock(name);
 119         if (!options.isEmpty()) {
 120             Object handler = options.get("show");
 121             if (canBeRun(handler)) {
 122                 LOG.trace("Showing {} with show: handler", name);
 123                 run(handler, name, window);
 124                 return;
 125             } else if (options.get(HANDLER) instanceof WindowDisplayHandler) {
 126                 LOG.trace("Showing {} with handler: handler", name);
 127                 ((WindowDisplayHandler<W>) options.get(HANDLER)).show(name, window);
 128                 return;
 129             }
 130         }
 131
 132         if (handleShowByInjectedHandler(name, window)) {
 133             return;
 134         }
 135
 136         options = windowManagerBlock();
 137         if (!options.isEmpty()) {
 138             Object defaultShow = options.get("defaultShow");
 139             if (canBeRun(defaultShow)) {
 140                 LOG.trace("Showing {} with defaultShow: handler", name);
 141                 run(defaultShow, name, window);
 142                 return;
 143             }
 144         }
 145
 146         LOG.trace("Showing {} with default handler", name);
 147         fetchDefaultWindowDisplayHandler().show(name, window);
 148     }
 149
 150     @SuppressWarnings("unchecked")
 151     public void hide(@Nonnull String name, @Nonnull W window) {
 152         requireNonBlank(name, ERROR_NAME_BLANK);
 153         requireNonNull(window, ERROR_WINDOW_NULL);
 154
 155         Map<String, Object> options = windowBlock(name);
 156         if (!options.isEmpty()) {
 157             Object handler = options.get("hide");
 158             if (canBeRun(handler)) {
 159                 LOG.trace("Hiding {} with hide: handler", name);
 160                 run(handler, name, window);
 161                 return;
 162             } else if (options.get(HANDLER) instanceof WindowDisplayHandler) {
 163                 LOG.trace("Hiding {} with handler: handler", name);
 164                 ((WindowDisplayHandler<W>) options.get(HANDLER)).hide(name, window);
 165                 return;
 166             }
 167         }
 168
 169         if (handleHideByInjectedHandler(name, window)) {
 170             return;
 171         }
 172
 173         options = windowManagerBlock();
 174         if (!options.isEmpty()) {
 175             Object defaultHide = options.get("defaultHide");
 176             if (canBeRun(defaultHide)) {
 177                 LOG.trace("Hiding {} with defaultHide: handler", name);
 178                 run(defaultHide, name, window);
 179                 return;
 180             }
 181         }
 182
 183         LOG.trace("Hiding {} with default handler", name);
 184         fetchDefaultWindowDisplayHandler().hide(name, window);
 185     }
 186
 187     @SuppressWarnings("unchecked")
 188     protected boolean handleShowByInjectedHandler(@Nonnull String name, @Nonnull W window) {
 189         try {
 190             WindowDisplayHandler<W> handler = getApplication().getInjector()
 191                 .getInstance(WindowDisplayHandler.class, named(name));
 192             LOG.trace("Showing {} with injected handler", name);
 193             handler.show(name, window);
 194             return true;
 195         } catch (InstanceNotFoundException infe) {
 196             // ignore
 197         }
 198         return false;
 199     }
 200
 201     @SuppressWarnings("unchecked")
 202     protected boolean handleHideByInjectedHandler(@Nonnull String name, @Nonnull W window) {
 203         try {
 204             WindowDisplayHandler<W> handler = getApplication().getInjector()
 205                 .getInstance(WindowDisplayHandler.class, named(name));
 206             LOG.trace("Hiding {} with injected handler", name);
 207             handler.hide(name, window);
 208             return true;
 209         } catch (InstanceNotFoundException infe) {
 210             // ignore
 211         }
 212         return false;
 213     }
 214
 215     public WindowDisplayHandler<W> getDelegateWindowsDisplayHandler() {
 216         return delegateWindowsDisplayHandler;
 217     }
 218
 219     protected boolean canBeRun(@Nullable Object obj) {
 220         return obj instanceof RunnableWithArgs || obj instanceof CallableWithArgs;
 221     }
 222
 223     protected void run(@Nonnull Object handler, @Nonnull String name, @Nonnull W window) {
 224         if (handler instanceof RunnableWithArgs) {
 225             ((RunnableWithArgs) handler).run(name, window);
 226         } else if (handler instanceof CallableWithArgs) {
 227             ((CallableWithArgs<?>) handler).call(name, window);
 228         }
 229     }
 230
 231     protected Map<String, Object> windowManagerBlock() {
 232         return application.getConfiguration().get("windowManager", Collections.<String, Object>emptyMap());
 233     }
 234
 235     protected Map<String, Object> windowBlock(String windowName) {
 236         Map<String, Object> options = windowManagerBlock();
 237         return getConfigValue(options, windowName, Collections.<String, Object>emptyMap());
 238     }
 239
 240     protected GriffonApplication getApplication() {
 241         return application;
 242     }
 243
 244     @Nonnull
 245     @SuppressWarnings("unchecked")
 246     protected WindowDisplayHandler<W> fetchDefaultWindowDisplayHandler() {
 247         Object handler = windowManagerBlock().get("defaultHandler");
 248         return handler instanceof WindowDisplayHandler ? (WindowDisplayHandler<W>) handler : delegateWindowsDisplayHandler;
 249     }
 250 }
 |