| 
001 /*002  * Copyright 2008-2015 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.ApplicationEvent;
 019 import griffon.core.GriffonApplication;
 020 import griffon.core.env.ApplicationPhase;
 021 import griffon.core.event.EventRouter;
 022 import griffon.core.view.WindowDisplayHandler;
 023 import griffon.core.view.WindowManager;
 024 import griffon.exceptions.InstanceNotFoundException;
 025 import org.slf4j.Logger;
 026 import org.slf4j.LoggerFactory;
 027
 028 import javax.annotation.Nonnull;
 029 import javax.annotation.Nullable;
 030 import javax.inject.Inject;
 031 import java.util.Collection;
 032 import java.util.Collections;
 033 import java.util.LinkedHashMap;
 034 import java.util.List;
 035 import java.util.Map;
 036
 037 import static griffon.util.GriffonNameUtils.requireNonBlank;
 038 import static java.util.Arrays.asList;
 039 import static java.util.Collections.unmodifiableCollection;
 040 import static java.util.Objects.requireNonNull;
 041
 042 /**
 043  * @author Andres Almiray
 044  * @since 2.0.0
 045  */
 046 public abstract class AbstractWindowManager<W> implements WindowManager<W> {
 047     protected static final String ERROR_NAME_BLANK = "Argument 'name' must not be blank";
 048     protected static final String ERROR_WINDOW_NULL = "Argument 'window' must not be null";
 049     private static final Logger LOG = LoggerFactory.getLogger(AbstractWindowManager.class);
 050     private final Map<String, W> windows = Collections.synchronizedMap(new LinkedHashMap<String, W>());
 051
 052     private final GriffonApplication application;
 053     private final WindowDisplayHandler<W> windowDisplayHandler;
 054
 055     @Inject
 056     public AbstractWindowManager(@Nonnull GriffonApplication application, @Nonnull WindowDisplayHandler<W> windowDisplayHandler) {
 057         this.application = requireNonNull(application, "Argument 'application' must not be null");
 058         requireNonNull(application.getConfiguration(), "Argument 'application.configuration' must not be null");
 059         requireNonNull(application.getUIThreadManager(), "Argument 'application.uiThreadManager' must not be null");
 060         this.windowDisplayHandler = requireNonNull(windowDisplayHandler, "Argument 'windowDisplayHandler' must not be null");
 061     }
 062
 063     protected GriffonApplication getApplication() {
 064         return application;
 065     }
 066
 067     @Override
 068     @Nullable
 069     public W findWindow(@Nonnull String name) {
 070         requireNonBlank(name, ERROR_NAME_BLANK);
 071         return windows.get(name);
 072     }
 073
 074     @Override
 075     @Nullable
 076     public W getAt(int index) {
 077         synchronized (windows) {
 078             int size = windows.size();
 079             if (index < 0 || index >= size) {
 080                 throw new ArrayIndexOutOfBoundsException(index);
 081             }
 082
 083             int i = 0;
 084             for (W window : windows.values()) {
 085                 if (index == i++) {
 086                     return window;
 087                 }
 088             }
 089         }
 090         throw new ArrayIndexOutOfBoundsException(index);
 091     }
 092
 093     @Override
 094     @Nullable
 095     public W getStartingWindow() {
 096         W window;
 097         Object value = resolveStartingWindowFromConfiguration();
 098         LOG.debug("windowManager.startingWindow configured to {}", value);
 099
 100         if (value instanceof String) {
 101             String windowName = (String) value;
 102             LOG.debug("Selecting window {} as starting window", windowName);
 103             window = findWindow(windowName);
 104         } else if (value instanceof Number) {
 105             int index = ((Number) value).intValue();
 106             LOG.debug("Selecting window at index {} as starting window", index);
 107             window = getAt(index);
 108         } else {
 109             LOG.debug("No startingWindow configured, selecting the first one from the windows list");
 110             window = getAt(0);
 111         }
 112
 113         LOG.debug("Starting Window is {}", window);
 114
 115         return window;
 116     }
 117
 118     @Nullable
 119     protected Object resolveStartingWindowFromConfiguration() {
 120         return application.getConfiguration().get("windowManager.startingWindow", null);
 121     }
 122
 123     @Override
 124     @Nonnull
 125     public Collection<W> getWindows() {
 126         return unmodifiableCollection(windows.values());
 127     }
 128
 129     @Override
 130     public void attach(@Nonnull String name, @Nonnull W window) {
 131         requireNonBlank(name, ERROR_NAME_BLANK);
 132         requireNonNull(window, ERROR_WINDOW_NULL);
 133         if (windows.containsKey(name)) {
 134             W window2 = windows.get(name);
 135             if (window2 != window) {
 136                 detach(name);
 137             }
 138         }
 139
 140         doAttach(window);
 141
 142         LOG.debug("Attaching window with name: '{}' at index {} {}", name, windows.size(), window);
 143         windows.put(name, window);
 144         event(ApplicationEvent.WINDOW_ATTACHED, asList(name, window));
 145     }
 146
 147     protected abstract void doAttach(@Nonnull W window);
 148
 149     @Override
 150     public void detach(@Nonnull String name) {
 151         requireNonBlank(name, ERROR_NAME_BLANK);
 152         if (windows.containsKey(name)) {
 153             W window = windows.get(name);
 154
 155             doDetach(window);
 156
 157             LOG.debug("Detaching window with name: '{}' {}", name, window);
 158             windows.remove(name);
 159             event(ApplicationEvent.WINDOW_DETACHED, asList(name, window));
 160         }
 161     }
 162
 163     protected abstract void doDetach(@Nonnull W window);
 164
 165     @Override
 166     public void show(@Nonnull final W window) {
 167         requireNonNull(window, ERROR_WINDOW_NULL);
 168         if (!windows.containsValue(window)) {
 169             return;
 170         }
 171
 172         String windowName = null;
 173         int windowIndex = -1;
 174         synchronized (windows) {
 175             int i = 0;
 176             for (Map.Entry<String, W> entry : windows.entrySet()) {
 177                 if (entry.getValue() == window) {
 178                     windowName = entry.getKey();
 179                     windowIndex = i;
 180                     break;
 181                 }
 182                 i++;
 183             }
 184         }
 185
 186         final String name = windowName;
 187         final int index = windowIndex;
 188
 189         application.getUIThreadManager().runInsideUIAsync(new Runnable() {
 190             public void run() {
 191                 LOG.debug("Showing window with name: '{}' at index {} {}", name, index, window);
 192                 //noinspection ConstantConditions
 193                 resolveWindowDisplayHandler().show(name, window);
 194             }
 195         });
 196     }
 197
 198     @Override
 199     public void show(@Nonnull String name) {
 200         requireNonBlank(name, ERROR_NAME_BLANK);
 201         W window = findWindow(name);
 202         if (window != null) {
 203             show(window);
 204         }
 205     }
 206
 207     @Override
 208     public void hide(@Nonnull final W window) {
 209         requireNonNull(window, ERROR_WINDOW_NULL);
 210         if (!windows.containsValue(window)) {
 211             return;
 212         }
 213
 214         String windowName = null;
 215         int windowIndex = -1;
 216         synchronized (windows) {
 217             int i = 0;
 218             for (Map.Entry<String, W> entry : windows.entrySet()) {
 219                 if (entry.getValue() == window) {
 220                     windowName = entry.getKey();
 221                     windowIndex = i;
 222                     break;
 223                 }
 224                 i++;
 225             }
 226         }
 227
 228         final String name = windowName;
 229         final int index = windowIndex;
 230
 231         application.getUIThreadManager().runInsideUIAsync(new Runnable() {
 232             public void run() {
 233                 LOG.debug("Hiding window with name: '{}' at index {} {}", name, index, window);
 234                 //noinspection ConstantConditions
 235                 resolveWindowDisplayHandler().hide(name, window);
 236             }
 237         });
 238     }
 239
 240     @Nonnull
 241     protected WindowDisplayHandler<W> resolveWindowDisplayHandler() {
 242         return windowDisplayHandler;
 243     }
 244
 245     @Override
 246     public void hide(@Nonnull String name) {
 247         requireNonBlank(name, ERROR_NAME_BLANK);
 248         W window = findWindow(name);
 249         if (window != null) {
 250             hide(window);
 251         }
 252     }
 253
 254     @Override
 255     public boolean canShutdown(@Nonnull GriffonApplication app) {
 256         return true;
 257     }
 258
 259     @Override
 260     public void onShutdown(@Nonnull GriffonApplication app) {
 261         for (W window : windows.values()) {
 262             if (isWindowVisible(window)) hide(window);
 263         }
 264     }
 265
 266     protected abstract boolean isWindowVisible(@Nonnull W window);
 267
 268     @Override
 269     public int countVisibleWindows() {
 270         int visibleWindows = 0;
 271         for (W window : windows.values()) {
 272             if (isWindowVisible(window)) {
 273                 visibleWindows++;
 274             }
 275         }
 276         return visibleWindows;
 277     }
 278
 279     @Override
 280     public boolean isAutoShutdown() {
 281         return application.getConfiguration().getAsBoolean("application.autoShutdown", true);
 282     }
 283
 284     protected void event(@Nonnull ApplicationEvent evt, @Nonnull List<?> args) {
 285         event(evt.getName(), args);
 286     }
 287
 288     protected void event(@Nonnull String evt, @Nonnull List<?> args) {
 289         try {
 290             EventRouter eventRouter = getApplication().getEventRouter();
 291             eventRouter.publishEvent(evt, args);
 292         } catch (InstanceNotFoundException infe) {
 293             if (getApplication().getPhase() != ApplicationPhase.SHUTDOWN) {
 294                 throw infe;
 295             }
 296         }
 297     }
 298 }
 |