1 /*
2 * Copyright 2006-2016 The JGUIraffe Team.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License")
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.sf.jguiraffe.gui.builder.window;
17
18 import java.util.Collection;
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.Set;
22
23 import net.sf.jguiraffe.di.impl.SimpleBeanStoreImpl;
24
25 import org.apache.commons.jelly.JellyContext;
26
27 /**
28 * <p>
29 * A data class that stores important information needed during a window builder
30 * process.
31 * </p>
32 * <p>
33 * An instance of this class lives in the Jelly context during execution of a
34 * Jelly script that makes use of the window builder library. It contains
35 * parameters required by tag handler classes, e.g. the window manager to use.
36 * It will also store the results of the builder operation.
37 * </p>
38 * <p>
39 * In most cases a builder script will define only a single result window (if
40 * any). In this case the result window can be set using the
41 * {@link #setResultWindow(Window)} method and queried using
42 * {@link #getResultWindow()}. However, scripts are allowed to define multiple
43 * windows (an example use case would be a simple message box window which is
44 * displayed by an action of the main window). This can be achieved by giving
45 * the windows unique names; i.e. the {@code name} attribute of the window tag
46 * must be defined. Then, instead of {@link #setResultWindow(Window)}, the
47 * {@link #putWindow(String, Window)} method can be called to add the result
48 * window to this data object. {@link #putWindow(String, Window)} adds the
49 * window to an internal map so that it can be queried later by its name.
50 * </p>
51 * <p>
52 * Some objects managed by this class are available to the dependency injection
53 * framework (they can be obtained through the <code>BeanContext</code> of the
54 * active builder). These are the following:
55 * <ul>
56 * <li>The result window (provided that it already has been set) can be obtained
57 * using the key <em>{@value #KEY_CURRENT_WINDOW}</em>.</li>
58 * <li>Windows that have been assigned a name can be queried directly. The
59 * prefix <em>{@value #WINDOW_PREFIX}</em> has to be used, e.g. {@code
60 * window:msgBox} returns the window with the name <em>msgBox</em>.</li>
61 * <li>The parent window (if available) can be queried using the key
62 * <em>{@value #KEY_PARENT_WINDOW}</em>.</li>
63 * <li>If the current form bean is needed, it can be found in the context under
64 * the key <em>{@value #KEY_FORM_BEAN}</em>.</li>
65 * <li>Finally the active instance of this class can be obtained under the key
66 * <em>{@value #KEY_WINDOW_BUILDER_DATA}</em>.</li>
67 * </ul>
68 * </p>
69 *
70 * @author Oliver Heger
71 * @version $Id: WindowBuilderData.java 205 2012-01-29 18:29:57Z oheger $
72 */
73 public class WindowBuilderData implements SimpleBeanStoreImpl.BeanContributor
74 {
75 /**
76 * Constant for the key, under which the current result window can be
77 * obtained from the builder's bean context.
78 */
79 public static final String KEY_CURRENT_WINDOW = "CURRENT_WINDOW";
80
81 /**
82 * Constant for the key, under which the parent window can be obtained from
83 * the builder's bean context.
84 */
85 public static final String KEY_PARENT_WINDOW = "PARENT_WINDOW";
86
87 /**
88 * Constant for the key, under which the current form bean can be obtained
89 * from the builder's bean context.
90 */
91 public static final String KEY_FORM_BEAN = "FORM_BEAN";
92
93 /**
94 * Constant for the key, under which the instance of this class can be
95 * obtained from the builder's bean context.
96 */
97 public static final String KEY_WINDOW_BUILDER_DATA = "WINDOW_BUILDER_DATA";
98
99 /**
100 * Constant for the prefix for window beans. If a window is to be queried by
101 * its name, this prefix has to be used.
102 */
103 public static final String WINDOW_PREFIX = "window:";
104
105 /**
106 * Constant for the key under which an instance will be stored in the Jelly
107 * context.
108 */
109 private static final String CTX_KEY = WindowBuilderData.class.getName();
110
111 /** A map for the named windows. */
112 private final Map<String, Window> windows;
113
114 /** Stores a reference to the current window manager. */
115 private WindowManager windowManager;
116
117 /** Stores a reference to the parent window. */
118 private Window parentWindow;
119
120 /** Stores the result window. */
121 private Window resultWindow;
122
123 /** Stores the form bean instance. */
124 private Object formBean;
125
126 /** Stores the current Jelly context. */
127 private JellyContext context;
128
129 /**
130 * Creates a new instance of {@code WindowBuilderData}.
131 */
132 public WindowBuilderData()
133 {
134 windows = new HashMap<String, Window>();
135 }
136
137 /**
138 * Returns the form bean.
139 *
140 * @return the form bean
141 */
142 public Object getFormBean()
143 {
144 return formBean;
145 }
146
147 /**
148 * Sets the form bean. This information will be processed by form
149 * controllers that can use it to initialize forms and store user input.
150 *
151 * @param formBean the form bean
152 */
153 public void setFormBean(Object formBean)
154 {
155 this.formBean = formBean;
156 }
157
158 /**
159 * Returns the parent window of the new window.
160 *
161 * @return the parent window
162 */
163 public Window getParentWindow()
164 {
165 return parentWindow;
166 }
167
168 /**
169 * Sets the parent window. The newly created window will be a child of this
170 * window. For top level windows this property should be <b>null</b>.
171 *
172 * @param parentWindow the parent window
173 */
174 public void setParentWindow(Window parentWindow)
175 {
176 this.parentWindow = parentWindow;
177 }
178
179 /**
180 * Returns the result window of the builder process.
181 *
182 * @return the result window
183 */
184 public Window getResultWindow()
185 {
186 return resultWindow;
187 }
188
189 /**
190 * Sets the result window. Used by window creating tag handler classes to
191 * store their results.
192 *
193 * @param resultWindow the result window
194 */
195 public void setResultWindow(Window resultWindow)
196 {
197 this.resultWindow = resultWindow;
198 }
199
200 /**
201 * Returns the result window with the given name. Windows can be assigned a
202 * name. Using this name they can be queried. This is especially useful for
203 * builder scripts that define multiple windows. Using this method a
204 * specific window can be queried.
205 *
206 * @param name the name of the desired window
207 * @return the window with this name or <b>null</b> if it cannot be resolved
208 */
209 public Window getWindow(String name)
210 {
211 return windows.get(WINDOW_PREFIX + name);
212 }
213
214 /**
215 * Returns the current {@code JellyContext}. This information can be useful
216 * when access to objects local to the current build operation is needed.
217 * Note that this property is only initialized after this object was stored
218 * in the context. (This is the case while a build operation is executing.)
219 * If this method is called before a context is available, an
220 * {@code IllegalStateException} exception is thrown.
221 *
222 * @return the current {@code JellyContext}
223 * @throws IllegalStateException if the current context is not yet available
224 * @since 1.3
225 */
226 public JellyContext getContext()
227 {
228 if (context == null)
229 {
230 throw new IllegalStateException("Context not available! "
231 + "This method can only be called after this instance "
232 + "has been stored in the Jelly context using put().");
233 }
234 return context;
235 }
236
237 /**
238 * Adds a result window to this data object. This method can be called for
239 * each window created during the builder operation. If a name is specified,
240 * the window is stored in a map where it can be accessed later using this
241 * name (using {@link #getWindow(String)}). This method also invokes
242 * {@link #setResultWindow(Window)}, so that the passed in window becomes
243 * the result window. This means that if a script defines multiple windows,
244 * the last one becomes the official result window.
245 *
246 * @param name the name of the window; can be <b>null</b>, then the window
247 * cannot be queried using {@link #getWindow(String)}
248 * @param window the window to be added
249 */
250 public void putWindow(String name, Window window)
251 {
252 setResultWindow(window);
253
254 if (name != null)
255 {
256 windows.put(WINDOW_PREFIX + name, window);
257 }
258 }
259
260 /**
261 * Returns the window manager.
262 *
263 * @return the window manager
264 */
265 public WindowManager getWindowManager()
266 {
267 return windowManager;
268 }
269
270 /**
271 * Sets the window manager. Here the platform specific window manager must
272 * be set, which will be used for creating windows.
273 *
274 * @param windowManager the window manager to use
275 */
276 public void setWindowManager(WindowManager windowManager)
277 {
278 this.windowManager = windowManager;
279 }
280
281 /**
282 * Obtains the names of the supported beans. This implementation adds the
283 * names of some static beans. If there are named windows, their names are
284 * added as well.
285 *
286 * @param names a set in which to store the bean names
287 */
288 public void beanNames(Set<String> names)
289 {
290 addBeanName(names, KEY_CURRENT_WINDOW, getResultWindow());
291 addBeanName(names, KEY_FORM_BEAN, getFormBean());
292 addBeanName(names, KEY_PARENT_WINDOW, getParentWindow());
293
294 for (String name : windows.keySet())
295 {
296 names.add(name);
297 }
298 }
299
300 /**
301 * Returns the bean with the specified name. This implementation supports a
302 * few objects that are managed by this object. Named windows can also be
303 * queried.
304 *
305 * @param name the name of the desired bean
306 * @return the bean with this name or <b>null</b> if it cannot be found
307 */
308 public Object getBean(String name)
309 {
310 Object bean = null;
311
312 if (KEY_CURRENT_WINDOW.equals(name))
313 {
314 bean = getResultWindow();
315 }
316 else if (KEY_FORM_BEAN.equals(name))
317 {
318 bean = getFormBean();
319 }
320 else if (KEY_PARENT_WINDOW.equals(name))
321 {
322 bean = getParentWindow();
323 }
324 else if (name.startsWith(WINDOW_PREFIX))
325 {
326 bean = windows.get(name);
327 }
328
329 return bean;
330 }
331
332 /**
333 * Initializes the specified bean store. This implementation adds the static
334 * object references to the store and registers this object as bean
335 * contributor.
336 *
337 * @param store the store to be initialized
338 */
339 public void initBeanStore(SimpleBeanStoreImpl store)
340 {
341 store.addBean(KEY_WINDOW_BUILDER_DATA, this);
342 store.addBeanContributor(this);
343 }
344
345 /**
346 * Stores this instance in the specified Jelly context.
347 *
348 * @param ctx the context (must not be <b>null</b>)
349 * @throws IllegalArgumentException if the context is <b>null</b>
350 */
351 public void put(JellyContext ctx)
352 {
353 if (ctx == null)
354 {
355 throw new IllegalArgumentException("Context must not be null!");
356 }
357 ctx.setVariable(CTX_KEY, this);
358 context = ctx;
359 }
360
361 /**
362 * Returns the instance of this class stored in the specified Jelly context.
363 * If no instance can be found, <b>null</b> will be returned.
364 *
365 * @param context the Jelly context
366 * @return the instance found in this context
367 */
368 public static WindowBuilderData get(JellyContext context)
369 {
370 return (context != null) ? (WindowBuilderData) context
371 .findVariable(CTX_KEY) : null;
372 }
373
374 /**
375 * Helper method for adding a bean name to a collection only if the bean is
376 * not <b>null</b>.
377 *
378 * @param col the collection
379 * @param name the name
380 * @param bean the bean
381 */
382 private static void addBeanName(Collection<String> col, String name,
383 Object bean)
384 {
385 if (bean != null)
386 {
387 col.add(name);
388 }
389 }
390 }