|
|||||||||||||||||||
| 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 |
|
||||||||||