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