|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
AbstractUIController.java | 100% | 89.7% | 71.4% | 85.7% |
|
1 | /* | |
2 | * Copyright (c) 1998, 2005 Gargoyle Software Inc. All rights reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions are met: | |
6 | * | |
7 | * 1. Redistributions of source code must retain the above copyright notice, | |
8 | * this list of conditions and the following disclaimer. | |
9 | * 2. Redistributions in binary form must reproduce the above copyright notice, | |
10 | * this list of conditions and the following disclaimer in the documentation | |
11 | * and/or other materials provided with the distribution. | |
12 | * 3. The end-user documentation included with the redistribution, if any, must | |
13 | * include the following acknowledgment: | |
14 | * | |
15 | * "This product includes software developed by Gargoyle Software Inc. | |
16 | * (http://www.GargoyleSoftware.com/)." | |
17 | * | |
18 | * Alternately, this acknowledgment may appear in the software itself, if | |
19 | * and wherever such third-party acknowledgments normally appear. | |
20 | * 4. The name "Gargoyle Software" must not be used to endorse or promote | |
21 | * products derived from this software without prior written permission. | |
22 | * For written permission, please contact info@GargoyleSoftware.com. | |
23 | * 5. Products derived from this software may not be called "GSBase", nor may | |
24 | * "GSBase" appear in their name, without prior written permission of | |
25 | * Gargoyle Software Inc. | |
26 | * | |
27 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, | |
28 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
29 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE | |
30 | * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
32 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | |
33 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
34 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
35 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
36 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
37 | */ | |
38 | package com.gargoylesoftware.base.gui; | |
39 | ||
40 | import com.gargoylesoftware.base.util.DetailedNullPointerException; | |
41 | import java.util.Locale; | |
42 | import javax.swing.SwingUtilities; | |
43 | ||
44 | /** | |
45 | * An abstract superclass for GUI controller classes.<p> | |
46 | * | |
47 | * Swing uses an architecture similar to Model-View-Controller (MVC) in which the model, view | |
48 | * and controller components are kept seperate from each other. This class provides | |
49 | * some common behaviour that is useful for controller objects. This includes support for: | |
50 | * <ul> | |
51 | * | |
52 | * <li>Starting and managing worker threads. See {@link #startTask(WorkerTask)}, | |
53 | * {@link #taskComplete(WorkerTask)}, {@link #taskSuccessful(WorkerTask)}, | |
54 | * {@link #taskExceptionThrown(WorkerTask,Exception)}, | |
55 | * {@link #taskErrorThrown(WorkerTask,Throwable)} | |
56 | * <br /> </li> | |
57 | * | |
58 | * <li>Simple support for localization. See {@link #setLocale(Locale)}, | |
59 | * {@link #getLocale()}, {@link #localeChanged(Locale)}</li> | |
60 | * | |
61 | * </ul> | |
62 | * | |
63 | * @version $Revision: 1.7 $ | |
64 | * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> | |
65 | */ | |
66 | public abstract class AbstractUIController { | |
67 | private Locale locale_ = Locale.getDefault(); | |
68 | ||
69 | ||
70 | private class TaskRunnable implements Runnable { | |
71 | private Throwable throwable_; | |
72 | private final WorkerTask task_; | |
73 | ||
74 | /** | |
75 | * Create an instance | |
76 | * @param task The task that will be run | |
77 | */ | |
78 | 6 | public TaskRunnable( final WorkerTask task ) { |
79 | 6 | task_ = task; |
80 | } | |
81 | ||
82 | /** Run the task */ | |
83 | 6 | public void run() { |
84 | ||
85 | 6 | try { |
86 | 6 | task_.runOnWorkerThread(); |
87 | } | |
88 | catch( final Throwable t ) { | |
89 | 2 | throwable_ = t; |
90 | } | |
91 | 6 | SwingUtilities.invokeLater( |
92 | new Runnable() { | |
93 | 6 | public void run() { |
94 | 6 | try { |
95 | 6 | run2(); |
96 | } | |
97 | catch( final Throwable t ) { | |
98 | 0 | t.printStackTrace(); |
99 | } | |
100 | } | |
101 | 6 | public void run2() { |
102 | 6 | if( throwable_ != null ) { |
103 | 2 | if( throwable_ instanceof Exception ) { |
104 | 1 | taskExceptionThrown( task_, |
105 | (Exception)throwable_ ); | |
106 | } | |
107 | else { | |
108 | 1 | taskErrorThrown( task_, throwable_ ); |
109 | } | |
110 | } | |
111 | else { | |
112 | 4 | try { |
113 | 4 | task_.runOnUIThread(); |
114 | 2 | taskSuccessful( task_ ); |
115 | } | |
116 | catch( final Exception e ) { | |
117 | 1 | taskExceptionThrown( task_, e ); |
118 | } | |
119 | catch( final Throwable t ) { | |
120 | 1 | taskErrorThrown( task_, t ); |
121 | } | |
122 | } | |
123 | 6 | taskComplete( task_ ); |
124 | } | |
125 | } ); | |
126 | } | |
127 | } | |
128 | ||
129 | ||
130 | /** | |
131 | * Create a new controller. | |
132 | */ | |
133 | 8 | public AbstractUIController() { |
134 | } | |
135 | ||
136 | ||
137 | /** | |
138 | * Set the current locale | |
139 | * | |
140 | * @param locale the new locale | |
141 | */ | |
142 | 2 | public final void setLocale( final Locale locale ) { |
143 | 2 | assertNotNull("locale", locale); |
144 | 1 | locale_ = locale; |
145 | 1 | localeChanged( locale_ ); |
146 | } | |
147 | ||
148 | ||
149 | /** | |
150 | * Return the current locale. | |
151 | * | |
152 | * @return The current locale | |
153 | */ | |
154 | 3 | public final Locale getLocale() { |
155 | 3 | return locale_; |
156 | } | |
157 | ||
158 | ||
159 | /** | |
160 | * The main entry point into this controller | |
161 | */ | |
162 | 1 | public final void run() { |
163 | 1 | localeChanged( getLocale() ); |
164 | 1 | runImpl(); |
165 | } | |
166 | ||
167 | ||
168 | /** | |
169 | * Subclasses will override this to provide the run logic | |
170 | */ | |
171 | protected abstract void runImpl(); | |
172 | ||
173 | ||
174 | /** | |
175 | * Start a WorkerTask. This involves running some code on a background | |
176 | * thread and then some more on the ui thread. See WorkerTask for more | |
177 | * details. <p> | |
178 | * | |
179 | * When the task has completed, one of the following callbacks will be | |
180 | * called based on the success of the task. | |
181 | * <ul> | |
182 | * <li> If the task completed without error then {@link | |
183 | * #taskSuccessful(com.gargoylesoftware.base.gui.WorkerTask) | |
184 | * taskSuccessful()} will be called | |
185 | * <li> If an exception was thrown during processing of the task then | |
186 | * {@link #taskExceptionThrown(com.gargoylesoftware.base.gui.WorkerTask,Exception) | |
187 | * taskExceptionThrown()} will be called | |
188 | * <li> If an error was thrown during processing of the task then {@link | |
189 | * #taskErrorThrown(com.gargoylesoftware.base.gui.WorkerTask,Throwable) | |
190 | * taskErrorThrown()} will be called | |
191 | * </ul> | |
192 | * <br /> | |
193 | * Finally, the method {@link #taskComplete(com.gargoylesoftware.base.gui.WorkerTask) | |
194 | * taskSuccessful()} will be called will be called to signal the completion | |
195 | * of the task | |
196 | * | |
197 | * @param task The WorkerTask that is about to execute. | |
198 | */ | |
199 | 6 | protected final void startTask( final WorkerTask task ) { |
200 | 6 | new Thread( new TaskRunnable(task) ).start(); |
201 | } | |
202 | ||
203 | ||
204 | /** | |
205 | * A callback that will be invoked when an exception is thrown during the | |
206 | * processing of a WorkerTask. Note that errors and other throwables will | |
207 | * processed by the method {@link #taskErrorThrown(WorkerTask,Throwable)}.<p> | |
208 | * | |
209 | * The default behaviour is to print the stack trace of the caught exception | |
210 | * to System.out. Override this method to provide custom error handling. | |
211 | * | |
212 | * @param task The task that failed | |
213 | * @param exception The exception that was caught. | |
214 | */ | |
215 | 0 | protected void taskExceptionThrown( final WorkerTask task, final Exception exception ) { |
216 | 0 | exception.printStackTrace(); |
217 | } | |
218 | ||
219 | ||
220 | /** | |
221 | * A callback that will be invoked when a system error is thrown during the | |
222 | * processing of a WorkerTask. System errors are any throwable objects not | |
223 | * descended from Exception. Typically, only system level code will be | |
224 | * concerned by the errors handled by this method. Application code should | |
225 | * only be concerned with the errors handled by | |
226 | * {@link #taskExceptionThrown(WorkerTask,Exception)}. | |
227 | * | |
228 | * The default behaviour is to print the stack trace of the caught error | |
229 | * to System.out. Override this method to provide custom error handling. | |
230 | * | |
231 | * @param task The task that failed | |
232 | * @param throwable The throwable object that was caught | |
233 | */ | |
234 | 0 | protected void taskErrorThrown( final WorkerTask task, final Throwable throwable ) { |
235 | 0 | throwable.printStackTrace(); |
236 | } | |
237 | ||
238 | ||
239 | /** | |
240 | * A callback that will be invoked when a task completed successfully. | |
241 | * Override this method to provide custom handling on completion | |
242 | * of a task.<p> | |
243 | * | |
244 | * The default behaviour is to do nothing. Override this to provide custom | |
245 | * behaviour. | |
246 | * | |
247 | * @param task The task that just finished. | |
248 | */ | |
249 | 0 | protected void taskSuccessful( final WorkerTask task ) { |
250 | } | |
251 | ||
252 | ||
253 | /** | |
254 | * A callback that will be invoked when a task has completed whether it was | |
255 | * successful or not. Override this method to provide custom handling on | |
256 | * completion of a task. | |
257 | * | |
258 | * The default behaviour is to do nothing. Override this to provide custom | |
259 | * behaviour. | |
260 | * | |
261 | * @param task The task that just finished. | |
262 | */ | |
263 | 0 | protected void taskComplete( final WorkerTask task ) { |
264 | } | |
265 | ||
266 | ||
267 | /** | |
268 | * The current locale has changed - update all locale specific information. | |
269 | * All logic that sets locale sensitive information should be executed in | |
270 | * this method. | |
271 | * | |
272 | * @param locale The new locale | |
273 | */ | |
274 | protected abstract void localeChanged( final Locale locale ); | |
275 | ||
276 | ||
277 | /** | |
278 | * Throw an exception if the specified object is null | |
279 | * @param fieldName The name of the paremeter we are checking | |
280 | * @param object The value of the parameter we are checking | |
281 | */ | |
282 | 2 | protected final void assertNotNull( final String fieldName, final Object object ) { |
283 | 2 | if( object == null ) { |
284 | 1 | throw new DetailedNullPointerException("fieldName"); |
285 | } | |
286 | } | |
287 | } | |
288 |
|