001 /*
002 * This file is part of the Echo Point Project. This project is a
003 * collection of Components that have extended the Echo Web Application
004 * Framework Version 3.
005 *
006 * Version: MPL 1.1
007 *
008 * The contents of this file are subject to the Mozilla Public License Version
009 * 1.1 (the "License"); you may not use this file except in compliance with
010 * the License. You may obtain a copy of the License at
011 * http://www.mozilla.org/MPL/
012 *
013 * Software distributed under the License is distributed on an "AS IS" basis,
014 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
015 * for the specific language governing rights and limitations under the
016 * License.
017 */
018 package echopoint.tucana;
019
020 import echopoint.ProgressBar;
021 import echopoint.internal.AbstractContainer;
022 import echopoint.tucana.event.DefaultUploadListener;
023 import echopoint.tucana.event.InvalidContentTypeEvent;
024 import echopoint.tucana.event.UploadCallback;
025 import echopoint.tucana.event.UploadCancelEvent;
026 import echopoint.tucana.event.UploadEvent;
027 import echopoint.tucana.event.UploadFailEvent;
028 import echopoint.tucana.event.UploadFinishEvent;
029 import echopoint.tucana.event.UploadProgressEvent;
030 import echopoint.tucana.event.UploadStartEvent;
031 import nextapp.echo.app.ApplicationInstance;
032 import nextapp.echo.app.Component;
033 import nextapp.echo.app.ImageReference;
034 import nextapp.echo.app.TaskQueueHandle;
035 import nextapp.echo.app.event.ActionEvent;
036 import nextapp.echo.app.event.ActionListener;
037
038 import java.util.Collections;
039 import java.util.HashSet;
040 import java.util.Set;
041
042 /**
043 * The file upload selector component. This component is a re-implementation
044 * of the original <i>tucana file upload selector</i> component for Echo2.
045 *
046 * <p><b>Note:</b> It is critical that this component be set absolute height
047 * and width properties. Percentage based values can cause problems if using
048 * a progress bar.</p>
049 *
050 * <p>The following code shows sample usage of this component:</p>
051 * <pre>
052 * import nextapp.echo.app.Border;
053 * import nextapp.echo.app.Color;
054 * import echopoint.tucana.ButtonMode;
055 * import echopoint.tucana.ButtonDisplay;
056 * import echopoint.tucana.FileUploadSelector;
057 * import echopoint.tucana.ProgressBar;
058 * import static echopoint.tucana.UploadSPI;
059 * import echopoint.tucana.event.DefaultUploadCallback;
060 *
061 * ...
062 * final FileUploadSelector selector = new FileUploadSelector();
063 * selector.setButtonMode( ButtonMode.image );
064 * selector.setButtonDisplayMode( ButtonDisplay.right );
065 * selector.setInputSize( 20 );
066 * selector.setUploadSizeLimit( NO_SIZE_LIMIT );
067 * selector.setBackground( new Color( 0xa1a1a1 ) );
068 * selector.setBorder( new Border( 1, Color.BLUE, Border.STYLE_GROOVE ) );
069 * selector.setProgressBar( new ProgressBar() );
070 * selector.setUploadCallback( new DefaultUploadCallback( new File( "/tmp" ) ) );
071 * selector.addActionListener( ... );
072 *
073 * // Allow only the following types of files to be uploaded.
074 * final HashSet<String> set = new HashSet<String>();
075 * set.add( "image/gif" );
076 * set.add( "image/jpeg" );
077 * set.add( "image/png" );
078 * selector.setContentTypeFilter( set );
079 *
080 * parent.add( selector );
081 * </pre>
082 *
083 * <p>There are two different (equivalent) ways to process a completed upload:
084 * <ol>
085 * <li>{@link echopoint.tucana.event.UploadCallback} based. It is best
086 * to use a sub-class of either {@link echopoint.tucana.event.DefaultUploadCallback}
087 * or {@link echopoint.tucana.event.UploadCallbackAdapter} since they
088 * ensure removal of the task queue used to enqueue processing from the
089 * call back methods to the UI thread. If you sub-class please note that
090 * calls to {@code super.uploadXxx} methods should be invoked at the end
091 * of your over-ridden implementation and not at the top. The super class
092 * implementations destroys the queue and sets it to {@code null}.
093 * If you implement your own handler
094 * please make sure that you invoke {@link FileUploadSelector#removeTaskQueue()}
095 * at the end of your handler methods. The queue will be automatically
096 * cleaned up when the component is removed from the hierarchy, so it may
097 * be acceptable to not invoke {@code removeTaskQueue} depending upon how
098 * your application logic works.</li>
099 * <li>{@link nextapp.echo.app.event.ActionListener} based. Two types of
100 * events are recieved by the event handler:
101 * <ol>
102 * <li>{@link #START_ACTION} - The action command that indicates that
103 * the file upload has commenced.</li>
104 * <li>{@link #COMPLETE_ACTION} - The action command that indicates that
105 * the file upload has finished.</li>
106 * </ol>
107 * <p>Please note that it is safest to check on the command value rather
108 * than check one and default action for the other value.</p>
109 * </li>
110 * </ol>
111 *
112 * <p>The following callback class and associated runnable may be used to
113 * update the UI after an upload.</p>
114 * <pre>
115 * import nextapp.echo.app.ApplicationInstance;
116 * import nextapp.echo.app.Component;
117 * import nextapp.echo.app.TaskQueueHandle;
118 * import echopoint.DirectHtml;
119 * import echopoint.tucana.event.UploadCallbackAdapter;
120 *
121 * public class UploadCallbackImpl extends UploadCallbackAdapter
122 * {
123 * private static final long serialVersionUID = 1l;
124 * private final Component parent;
125 *
126 * private UploadCallbackImpl( final Component parent )
127 * {
128 * this.parent = parent;
129 * }
130 *
131 * @Override
132 * public void uploadSucceeded( final UploadFinishEvent event )
133 * {
134 * final StringBuilder builder = new StringBuilder( 128 );
135 * builder.append( "Upload of file: <b>" );
136 * builder.append( event.getFileName() );
137 * builder.append( "</b> succeeded. File size is: <i>");
138 * builder.append( event.getFileSize() / 1000 );
139 * builder.append( "</i> kilobytes." );
140 * final DirectHtml html = new DirectHtml( builder.toString() );
141 * parent.add( child );
142 * super.uploadSucceeded( event );
143 * }
144 *
145 * @Override
146 * public void uploadFailed( final UploadFailEvent event )
147 * {
148 * final StringBuilder builder = new StringBuilder( 128 );
149 * builder.append( "File upload failed." );
150 * if ( event.getFileName() != null )
151 * {
152 * builder.append( " Failed file: <i>" );
153 * builder.append( event.getFileName() );
154 * builder.append( "</i>." );
155 * }
156 *
157 * if ( event.getException() != null )
158 * {
159 * builder.append( "Exception: <p><pre>" );
160 * builder.append( event.getException().toString() );
161 * builder.append( "</pre></p>" );
162 * }
163 *
164 * final DirectHtml html = new DirectHtml( builder.toString() );
165 * parent.add( child );
166 * super.uploadFailed( event );
167 * }
168 * </pre>
169 *
170 * <p>Processing UI updates after upload completion is much simpler (and
171 * more network friendly) when using an action listener. A simple action
172 * listener may be configured as follows:</p>
173 * <pre>
174 * import nextapp.echo.app.Component;
175 * import nextapp.echo.app.event.ActionEvent;
176 * import nextapp.echo.app.event.ActionListener;
177 * import echopoint.tucana.FileUploadSelector;
178 * import echopoint.tucana.event.UploadCallback;
179 * import echopoint.tucana.event.UploadFinishEvent;
180 * import echopoint.DirectHtml;
181 *
182 * public class FinishListener implements ActionListener
183 * {
184 * private static final long serialVersionUID = 1l;
185 *
186 * public void actionPerformed( final ActionEvent event )
187 * {
188 * final FileUploadSelector upload = ( FileUploadSelector) event.getSource();
189 * final UploadCallback callback = upload.getUploadCallback();
190 * if ( callback != null )
191 * {
192 * final StringBuilder builder = new StringBuilder( 128 );
193 * final boolean success = ( callback.getEvent() instanceof UploadFinishEvent );
194 *
195 * if ( success )
196 * {
197 * builder.append( "Upload of file: <b>" );
198 * builder.append( callback.getEvent().getFileName() );
199 * builder.append( "</b> succeeded. File size is: <i>");
200 * builder.append( callback.getEvent().getFileSize() / 1000 );
201 * builder.append( "</i> kilobytes." );
202 * }
203 * else
204 * {
205 * builder.append( "Upload " );
206 * if ( callback.getEvent() != null )
207 * {
208 * builder.append( " of file: <b>" );
209 * builder.append( callback.getEvent().getFileName() );
210 * builder.append( "</b>" );
211 * }
212 *
213 * builder.append( " failed/cancelled." );
214 * }
215 *
216 * upload.getParent().add( new DirectHtml( builder.toString() ) );
217 *
218 * if ( upload.getProgressBar() != null )
219 * {
220 * upload.getProgressBar().setText( ( success ) ?
221 * "Finished upload!" : "Cancelled upload!" );
222 * }
223 * }
224 * }
225 * }
226 * </pre>
227 *
228 * <p><b>Note:</b> Development of this component was sponsored by <a
229 * href='http://tcnbroadcasting.com/index.jsp' target='_top'>TCN
230 * Broadcasting</a>. We are grateful for their support and sponsorship.</p>
231 *
232 * @author jvolkman (Echo2), Rakesh 2008-11-2
233 * @version $Id: FileUploadSelector.java 204 2009-05-20 18:50:57Z sptrakesh $
234 */
235 public class FileUploadSelector extends AbstractContainer
236 {
237 private static final long serialVersionUID = 1l;
238
239 public static final String PROPERTY_BUTTON_TEXT_UPLOAD = "buttonTextUpload";
240
241 public static final String PROPERTY_BUTTON_TEXT_CANCEL = "buttonTextCancel";
242
243 public static final String PROPERTY_BUTTON_TEXT_WAIT = "buttonTextWait";
244
245 public static final String PROPERTY_BUTTON_IMAGE_UPLOAD = "buttonImageUpload";
246
247 public static final String PROPERTY_BUTTON_IMAGE_CANCEL = "buttonImageCancel";
248
249 public static final String PROPERTY_BUTTON_IMAGE_WAIT = "buttonImageWait";
250
251 public static final String PROPERTY_BUTTON_MODE = "buttonMode";
252
253 public static final String PROPERTY_BUTTON_DISPLAY = "buttonDisplay";
254
255 public static final String PROPERTY_CANCEL_ENABLED = "cancelEnabled";
256
257 /**
258 * The size (indicates number of characters) for the input field.
259 * This is the same as the old <code>PROPERTY_WIDTH_SIZE</code>.
260 * This property is best styled.
261 */
262 public static final String PROPERTY_INPUT_SIZE = "inputSize";
263
264 /**
265 * The interval (in milliseconds) at which the progress service is
266 * to be polled for updates. Note that upload completion and cancellation
267 * are inferred through the response from the service. This property
268 * is best styled.
269 */
270 public static final String PROPERTY_POLLING_INTERVAL = "pollingInterval";
271
272 /** The maximum size of file that is allowed to be uploaded. */
273 public static final String PROPERTY_UPLOAD_SIZE_LIMIT = "uploadSizeLimit";
274
275 /**
276 * The name of the action that is fired by the client upon completion
277 * (regardless of complete or cancel) of the upload process.
278 *
279 * {@value}
280 */
281 public static final String COMPLETE_ACTION = "complete";
282
283 /**
284 * The name of the action that is fired by the client upon start
285 * of the upload process.
286 *
287 * {@value}
288 */
289 public static final String START_ACTION = "start";
290
291 /**
292 * The callback handler that will be notified of the progress of the file
293 * upload process.
294 */
295 private UploadCallback callback = null;
296
297 /**
298 * The allowed content-type(s) for the upload. Uploads of other types of
299 * files will be rejected.
300 */
301 private Set<String> contentTypeFilter = new HashSet<String>();
302
303 /**
304 * A task queue that may be used to perform UI updates from call back
305 * handlers. Automatically cleaned up in {@link #dispose}.
306 */
307 private TaskQueueHandle taskQueue;
308
309 /**
310 * Default constructor. Add {@link echopoint.tucana.event.DefaultUploadListener}
311 * as a listener for this component to initialise the {@link #taskQueue}.
312 */
313 public FileUploadSelector()
314 {
315 addActionListener( new DefaultUploadListener() );
316 }
317
318 /**
319 * Sets the upload button image.
320 *
321 * @param image The new upload button image.
322 */
323 public void setButtonUploadImage( final ImageReference image )
324 {
325 set( PROPERTY_BUTTON_IMAGE_UPLOAD, image );
326 }
327
328 /**
329 * Gets the current upload button image.
330 *
331 * @return The current upload button image.
332 */
333 public ImageReference getButtonUploadImage()
334 {
335 return (ImageReference) get( PROPERTY_BUTTON_IMAGE_UPLOAD );
336 }
337
338 /**
339 * Sets the cancel button image.
340 *
341 * @param image The new cancel button image.
342 */
343 public void setButtonCancelImage( final ImageReference image )
344 {
345 set( PROPERTY_BUTTON_IMAGE_CANCEL, image );
346 }
347
348 /**
349 * Gets the current cancel button image.
350 *
351 * @return The current cancel button image.
352 */
353 public ImageReference getButtonCancelImage()
354 {
355 return (ImageReference) get( PROPERTY_BUTTON_IMAGE_CANCEL );
356 }
357
358 /**
359 * Sets the wait button image.
360 *
361 * @param image The new wait button image.
362 */
363 public void setButtonWaitImage( final ImageReference image )
364 {
365 set( PROPERTY_BUTTON_IMAGE_WAIT, image );
366 }
367
368 /**
369 * Gets the current wait button image.
370 *
371 * @return The current wait button image.
372 */
373 public ImageReference getButtonWaitImage()
374 {
375 return (ImageReference) get( PROPERTY_BUTTON_IMAGE_WAIT );
376 }
377
378 /**
379 * Sets the upload button text.
380 *
381 * @param text The new upload button text.
382 */
383 public void setButtonUploadText( final String text )
384 {
385 set( PROPERTY_BUTTON_TEXT_UPLOAD, text );
386 }
387
388 /**
389 * Gets the current upload button text.
390 *
391 * @return The current upload button text.
392 */
393 public String getButtonUploadText()
394 {
395 return (String) get( PROPERTY_BUTTON_TEXT_UPLOAD );
396 }
397
398 /**
399 * Sets the cancel button text.
400 *
401 * @param text The new cancel button text.
402 */
403 public void setButtonCancelText( final String text )
404 {
405 set( PROPERTY_BUTTON_TEXT_CANCEL, text );
406 }
407
408 /**
409 * Gets the current cancel button text.
410 *
411 * @return The current cancel button text.
412 */
413 public String getButtonCancelText()
414 {
415 return (String) get( PROPERTY_BUTTON_TEXT_CANCEL );
416 }
417
418 /**
419 * Sets the wait button text.
420 *
421 * @param text The new wait button text.
422 */
423 public void setButtonWaitText( final String text )
424 {
425 set( PROPERTY_BUTTON_TEXT_WAIT, text );
426 }
427
428 /**
429 * Gets the current wait button text.
430 *
431 * @return The current wait button text.
432 */
433 public String getButtonWaitText()
434 {
435 return (String) get( PROPERTY_BUTTON_TEXT_WAIT );
436 }
437
438 /**
439 * Sets the upload button display mode
440 *
441 * @param mode The new upload button display mode
442 */
443 public void setButtonMode( final ButtonMode mode )
444 {
445 set( PROPERTY_BUTTON_MODE, mode );
446 }
447
448 /**
449 * Get the current upload button display mode.
450 *
451 * @return The current display mode, or {@link ButtonMode#submit} if not set.
452 */
453 public ButtonMode getButtonMode()
454 {
455 final ButtonMode mode = (ButtonMode) get( PROPERTY_BUTTON_MODE );
456 return ( mode == null ) ? ButtonMode.submit : mode;
457 }
458
459 /**
460 * Set the button display mode for the input submit button.
461 *
462 * @param mode Set to configure the location of the submit button.
463 */
464 public void setButtonDisplayMode( final ButtonDisplay mode )
465 {
466 set( PROPERTY_BUTTON_DISPLAY, mode );
467 }
468
469 /**
470 * Get the configuration for display of the submit button.
471 *
472 * @return The current mode, or {@link ButtonDisplay#auto} if not set.
473 */
474 public ButtonDisplay getButtonDisplayMode()
475 {
476 final ButtonDisplay display = (ButtonDisplay) get( PROPERTY_BUTTON_DISPLAY );
477 return ( display == null ) ? ButtonDisplay.auto : display;
478 }
479
480 /**
481 * Mutator for property 'cancelEnabled'.
482 *
483 * @param enabled Value to set for property 'cancelEnabled'.
484 */
485 public void setCancelEnabled( final boolean enabled )
486 {
487 set( PROPERTY_CANCEL_ENABLED, enabled );
488 }
489
490 /**
491 * Accessor for property 'cancelEnabled'.
492 *
493 * @return Value for property 'cancelEnabled'.
494 */
495 public boolean isCancelEnabled()
496 {
497 return ( (Boolean) get( PROPERTY_CANCEL_ENABLED ) );
498 }
499
500 /**
501 * Return the value of the {@link #PROPERTY_INPUT_SIZE} property.
502 *
503 * @return The size of the input text field.
504 */
505 public int getInputSize()
506 {
507 return (Integer) get( PROPERTY_INPUT_SIZE );
508 }
509
510 /**
511 * Set the value of the {@link #PROPERTY_INPUT_SIZE} property.
512 *
513 * @param size The size of the input text field.
514 */
515 public void setInputSize( final int size )
516 {
517 set( PROPERTY_INPUT_SIZE, size );
518 }
519
520 /**
521 * Return the value of the {@link #PROPERTY_POLLING_INTERVAL} property.
522 *
523 * @return The time interval at which the progress service will be polled
524 */
525 public int getPollingInterval()
526 {
527 return (Integer) get( PROPERTY_POLLING_INTERVAL );
528 }
529
530 /**
531 * Set the value of the {@link #PROPERTY_POLLING_INTERVAL} property.
532 *
533 * @param interval The time interval at which the progress service will be polled
534 */
535 public void setPollingInterval( final int interval )
536 {
537 set( PROPERTY_POLLING_INTERVAL, interval );
538 }
539
540 /**
541 * Return the value of the {@link #PROPERTY_UPLOAD_SIZE_LIMIT} property.
542 * If not set the implementation defaults to
543 * {@link echopoint.tucana.AbstractFileUploadProvider#DEFAULT_UPLOAD_SIZE_LIMIT}.
544 *
545 * @return The maximum size in bytes that is allowed to be uploaded.
546 */
547 public long getUploadSizeLimit()
548 {
549 final Object obj = get( PROPERTY_UPLOAD_SIZE_LIMIT );
550 return ( obj == null ) ? 0 : (Long) obj;
551 }
552
553 /**
554 * Set the value of the {@link #PROPERTY_UPLOAD_SIZE_LIMIT} property.
555 * Specify {@link echopoint.tucana.UploadSPI#NO_SIZE_LIMIT} to prevent
556 * size checking.
557 *
558 * @param limit The maximum size in bytes that is allowed.
559 */
560 public void setUploadSizeLimit( final long limit )
561 {
562 set( PROPERTY_UPLOAD_SIZE_LIMIT, limit );
563 }
564
565 /**
566 * Set the callback used when a file is uploaded.
567 *
568 * @param callback The upload callback.
569 */
570 public void setUploadCallback( final UploadCallback callback )
571 {
572 this.callback = callback;
573 }
574
575 /**
576 * Get the callback used when a file is uploaded.
577 *
578 * @return The upload callback.
579 */
580 public UploadCallback getUploadCallback()
581 {
582 return callback;
583 }
584
585 /**
586 * Return the progress bar component configured for this component.
587 *
588 * @return The progress bar if one was added or <code>null</code>.
589 */
590 public ProgressBar getProgressBar()
591 {
592 return ( getComponentCount() > 0 ) ? (ProgressBar) getComponent( 0 ) : null;
593 }
594
595 /**
596 * Add the specified progress bar to this component.
597 *
598 * @param progressBar The progress bar component to add.
599 */
600 public void setProgressBar( final ProgressBar progressBar )
601 {
602 add( progressBar, 0 );
603 }
604
605 /**
606 * Accessor for property 'contentTypeFilter'. Returns the content-types
607 * that are allowed to be uploaded by this component.
608 *
609 * @return Value for property 'contentTypeFilter'.
610 */
611 public Set<String> getContentTypeFilter()
612 {
613 return Collections.unmodifiableSet( contentTypeFilter );
614 }
615
616 /**
617 * Mutator for property 'contentTypeFilter'.
618 *
619 * @param contentTypeFilter Value to set for property 'contentTypeFilter'.
620 */
621 public void setContentTypeFilter( final Set<String> contentTypeFilter )
622 {
623 this.contentTypeFilter.clear();
624
625 if ( contentTypeFilter != null )
626 {
627 this.contentTypeFilter.addAll( contentTypeFilter );
628 }
629 }
630
631 /**
632 * The only allowed sub-component is a {@link echopoint.ProgressBar}.
633 *
634 * @param child The child component that is to be added if allowed.
635 * @return Return <code>true</code> if child is an instance of {@link
636 * echopoint.ProgressBar} and a progress bar has not already been
637 * assigned.
638 */
639 @Override
640 public boolean isValidChild( final Component child )
641 {
642 boolean result = ( child instanceof ProgressBar );
643 return result && ( getComponentCount() < 2 );
644 }
645
646 /**
647 * Return the task queue that may be used to enqueue asynchronous tasks
648 * (usually from callback handlers).
649 *
650 * @return Value for property 'taskQueue'.
651 */
652 public TaskQueueHandle getTaskQueue()
653 {
654 return taskQueue;
655 }
656
657 /**
658 * Set the task queue for the component.
659 *
660 * @param taskQueue Value to set for property 'taskQueue'.
661 */
662 public void setTaskQueue( final TaskQueueHandle taskQueue )
663 {
664 this.taskQueue = taskQueue;
665 }
666
667 /**
668 * Remove the current task queue. It is strongly recommended that this
669 * method be used rather than wait for {@link #dispose}.
670 */
671 public void removeTaskQueue()
672 {
673 if ( taskQueue != null )
674 {
675 ApplicationInstance.getActive().removeTaskQueue( taskQueue );
676 taskQueue = null;
677 }
678 }
679
680 /**
681 * Notifies the listener that the given event has occurred.
682 *
683 * @param e the event
684 */
685 protected void notifyCallback( final UploadEvent e )
686 {
687 if ( callback == null ) return;
688
689 if ( e instanceof UploadCancelEvent )
690 {
691 callback.uploadCancelled( (UploadCancelEvent) e );
692 }
693 if ( e instanceof InvalidContentTypeEvent )
694 {
695 callback.uploadDisallowed( (InvalidContentTypeEvent) e );
696 }
697 else if ( e instanceof UploadFailEvent )
698 {
699 callback.uploadFailed( (UploadFailEvent) e );
700 }
701 else if ( e instanceof UploadFinishEvent )
702 {
703 callback.uploadSucceeded( (UploadFinishEvent) e );
704 }
705 else if ( e instanceof UploadProgressEvent )
706 {
707 callback.uploadProgressed( (UploadProgressEvent) e );
708 }
709 else if ( e instanceof UploadStartEvent )
710 {
711 callback.uploadStarted( (UploadStartEvent) e );
712 }
713 }
714
715 /** {@inheritDoc} */
716 @Override
717 public void addActionListener( final ActionListener listener )
718 {
719 super.addActionListener( listener );
720 }
721
722 /** {@inheritDoc} */
723 @Override
724 public void removeActionListener( final ActionListener listener )
725 {
726 super.removeActionListener( listener );
727 }
728
729 /**
730 * Over-ridden to fire action events with action commands that are set to
731 * {@link #START_ACTION} or {@link #COMPLETE_ACTION} depending upon whether
732 * the event represents start of the upload or completion of the upload.
733 *
734 * @see nextapp.echo.app.Component#processInput(String, Object)
735 */
736 @Override
737 public void processInput( String name, Object value )
738 {
739 super.processInput( name, value );
740
741 if ( COMPLETE_ACTION.equals( name ) )
742 {
743 fireActionPerformed( new ActionEvent( this, name ) );
744 }
745 else if ( START_ACTION.equals( name ) )
746 {
747 fireActionPerformed( new ActionEvent( this, name ) );
748 }
749 }
750
751 /**
752 * Over-ridden to clean up {@link #taskQueue} if not already cleaned up.
753 *
754 * @see #removeTaskQueue()
755 * @see nextapp.echo.app.Component#dispose()
756 */
757 @Override
758 public void dispose()
759 {
760 removeTaskQueue();
761 }
762 }