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