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.app;
17
18 import net.sf.jguiraffe.gui.builder.Builder;
19 import net.sf.jguiraffe.gui.builder.window.Window;
20 import net.sf.jguiraffe.gui.cmd.CommandBase;
21 import net.sf.jguiraffe.locators.Locator;
22
23 /**
24 * <p>
25 * A specialized {@code Command} implementation for opening a sub window.
26 * </p>
27 * <p>
28 * This {@code Command} class provides functionality for opening sub frames or
29 * dialog boxes. An instance is initialized with the {@link Locator} to the
30 * builder script that defines the window. It executes this script in the worker
31 * thread and eventually displays the resulting window.
32 * </p>
33 * <p>
34 * Most applications need to open dialog boxes or other sub windows. With this
35 * command this can be done in a standard way. Using {@link CommandActionTask}
36 * an instance can be associated with an action. It is possible to define such
37 * an action completely in a builder script using the dependency injection
38 * framework. This can look as follows:
39 *
40 * <pre>
41 * <!-- Definition of the command bean for opening a dialog -->
42 * <di:bean name="openDialogCommand" singleton="false"
43 * beanClass="net.sf.jguiraffe.gui.app.OpenWindowCommand">
44 * <di:constructor>
45 * <di:param>
46 * <di:bean class="net.sf.jguiraffe.locators.ClassPathLocator">
47 * <di:factory>
48 * <di:methodInvocation method="getInstance">
49 * <di:param value="myDialog.jelly"/>
50 * </di:methodInvocation>
51 * </di:factory>
52 * </di:bean>
53 * </di:param>
54 * </di:constructor>
55 * </di:bean>
56 * <!-- The command task used by the action for opening a dialog -->
57 * <di:bean name="openDialogTask"
58 * beanClass="net.sf.jguiraffe.gui.app.CommandActionTask">
59 * <di:setProperty property="commandBeanName"
60 * value="openDialogCommand"/>
61 * <di:setProperty property="beforeEnabler">
62 * <di:bean beanClass="net.sf.jguiraffe.gui.builder.enablers.ActionEnabler">
63 * <di:constructor>
64 * <di:param value="openDialogAction"/>
65 * </di:constructor>
66 * </di:bean>
67 * </di:setProperty>
68 * </di:bean>
69 * <!-- The action for opening a dialog -->
70 * <a:action name="openDialogAction" text="Open dialog..."
71 * taskBean="openDialogTask"/>
72 * </pre>
73 *
74 * This fragment first defines the {@code OpenWindowCommand} bean. The bean is
75 * passed a newly created {@code Locator} object when it is constructed. Here a
76 * locator implementation is used that searches the builder script in the class
77 * path. It follows the definition of the action task bean. This is a
78 * {@link CommandActionTask} which is configured with our command bean. Note
79 * that also an <em>action enabler</em> is specified; this object disables the
80 * action while it is executed. Finally the action itself is defined. It
81 * references the task bean. The action can later be used to create a menu item
82 * or a button in a tool bar.
83 * </p>
84 *
85 * @author Oliver Heger
86 * @version $Id: OpenWindowCommand.java 205 2012-01-29 18:29:57Z oheger $
87 */
88 public class OpenWindowCommand extends CommandBase implements ApplicationClient
89 {
90 /** The locator to the builder script. */
91 private final Locator locator;
92
93 /** Stores the central application object. */
94 private Application application;
95
96 /** The window created in the background thread. */
97 private Window window;
98
99 /**
100 * Creates a new instance of {@code OpenWindowCommand} and initializes it
101 * with the {@code Locator} pointing to the builder script. The command will
102 * execute this builder script and display the resulting window.
103 *
104 * @param loc the {@code Locator} to the builder script (must not be
105 * <b>null</b>)
106 * @throws IllegalArgumentException if the {@code Locator} is <b>null</b>
107 */
108 public OpenWindowCommand(Locator loc)
109 {
110 super(true);
111 if (loc == null)
112 {
113 throw new IllegalArgumentException("Locator must not be null!");
114 }
115 locator = loc;
116 }
117
118 /**
119 * Returns the {@code Locator} to the builder script executed by this
120 * command.
121 *
122 * @return the {@code Locator}
123 */
124 public final Locator getLocator()
125 {
126 return locator;
127 }
128
129 /**
130 * Returns the central {@code Application} instance.
131 *
132 * @return the {@code Application}
133 */
134 public final Application getApplication()
135 {
136 return application;
137 }
138
139 /**
140 * Sets the central {@code Application} instance. From this object the
141 * {@code ApplicationContext} is obtained, which provides access to the
142 * builder. This method is typically called by the dependency injection
143 * framework.
144 *
145 * @param app the central {@code Application} object
146 */
147 public final void setApplication(Application app)
148 {
149 application = app;
150 }
151
152 /**
153 * <p>
154 * Executes this command. This implementation calls the builder to execute
155 * the builder script defining the window to be opened. Then the window is
156 * actually displayed.
157 * </p>
158 * <p>
159 * Note: This method does not implement a sophisticated exception handling.
160 * It expects the current {@code Locator} to be valid and to point to a
161 * builder script that actually returns a window. Otherwise, an exception is
162 * thrown which will be passed to the {@code onException()} method.
163 * </p>
164 * @throws Exception if an error occurs
165 */
166 public void execute() throws Exception
167 {
168 if (getApplication() == null)
169 {
170 throw new IllegalStateException("No Application reference set!");
171 }
172
173 Builder builder = getApplication().getApplicationContext().newBuilder();
174 ApplicationBuilderData builderData = getApplication()
175 .getApplicationContext().initBuilderData();
176 prepareBuilderData(builderData);
177
178 window = builder.buildWindow(getLocator(), builderData);
179 }
180
181 /**
182 * Updates the UI after background processing is complete. This
183 * implementation opens the window created in the background thread unless
184 * an exception occurred before.
185 */
186 @Override
187 protected void performGUIUpdate()
188 {
189 if (getException() == null)
190 {
191 assert getWindow() != null : "No window!";
192 getWindow().open();
193 }
194 }
195
196 /**
197 * Prepares the {@code ApplicationBuilderData} object. This method is called
198 * by {@code execute()} with the {@code ApplicationBuilderData} object
199 * obtained from the {@link ApplicationContext}. Derived classes can
200 * override it to perform custom initialization. This base implementation is
201 * empty.
202 *
203 * @param builderData the {@code ApplicationBuilderData} object to be
204 * initialized
205 */
206 protected void prepareBuilderData(ApplicationBuilderData builderData)
207 {
208 }
209
210 /**
211 * Returns the {@code Window} that was built in the background thread. This
212 * method is called by the GUI updater to obtain the window to be displayed.
213 * It exists mainly for testing purposes.
214 *
215 * @return the {@code Window} to be displayed
216 */
217 Window getWindow()
218 {
219 return window;
220 }
221 }