00001 import gugga.events.EventDispatcher;
00002 import mx.utils.Delegate;
00003
00004 import gugga.application.ISectionsController;
00005 import gugga.application.Section;
00006 import gugga.application.TransitionInfo;
00007 import gugga.common.EventDescriptor;
00008 import gugga.common.IProgressiveTask;
00009 import gugga.common.ITask;
00010 import gugga.components.ISectionLoader;
00011 import gugga.components.SectionAttacher;
00012 import gugga.components.SectionLoader;
00013 import gugga.sequence.FictiveTask;
00014 import gugga.sequence.PreconditionsTask;
00015 import gugga.sequence.ProgressMonitor;
00016 import gugga.utils.DoLaterUtil;
00017 import gugga.utils.Listener;
00018
00019 [Event("lazyTargetSectionAvailable")]
00020 [Event("lazyTargetSectionUIInitialized")]
00021 [Event("lazyTargetSectionInitialized")]
00022
00023 [Event("targetSectionActivate")]
00024 [Event("targetSectionOpen")]
00025
00026 [Event("currentSectionDestroyed")]
00027 [Event("currentSectionClose")]
00028 [Event("currentSectionDestroy")]
00029
00030 [Event("setNavigationLock")]
00031 [Event("clearNavigationLock")]
00032
00033 [Event("sectionsSwapped")]
00034
00035 [Event("disposed")]
00036
00040 class gugga.application.SectionsTransition
00041 extends EventDispatcher
00042 implements ITask
00043 {
00044 private var mOpenTargetSectionPreconditions : PreconditionsTask;
00045 private var mDisposePreconditions : PreconditionsTask;
00046
00047 private var mDoLoadTargetSection : Boolean;
00048 private var mDetachCurrentSectionAfterClose : Boolean;
00049 private var mSectionPathRest : String;
00050
00051 private var mChildSectionsTransition : SectionsTransition;
00052
00053 private var mIsRunning : Boolean = false;
00054 private var mIsInterrupting : Boolean = false;
00055
00056 private var mTargetSectionInitializedTask : FictiveTask;
00057
00058 private var mPreOpenProgressMonitor : ProgressMonitor;
00059 public function get PreOpenProgressMonitor() : ProgressMonitor { return mPreOpenProgressMonitor; }
00060
00061 private var mSectionsController : ISectionsController;
00062 public function get SectionsController() : ISectionsController { return mSectionsController; }
00063
00064 private var mCurrentSection : Section;
00065 public function get CurrentSection() : Section { return mCurrentSection; }
00066
00067 private var mTargetSection : Section;
00068 public function get TargetSection() : Section { return mTargetSection; }
00069
00070 private var mTargetSectionLoader : ISectionLoader;
00071 public function get TargetSectionLoader() : ISectionLoader { return mTargetSectionLoader; }
00072
00073 public function SectionsTransition(aTransitionInfo:TransitionInfo)
00074 {
00075 mSectionsController = aTransitionInfo.SectionsController;
00076 mCurrentSection = aTransitionInfo.CurrentSection;
00077 mDetachCurrentSectionAfterClose = aTransitionInfo.DetachCurrentSectionAfterClose;
00078 mTargetSection = aTransitionInfo.TargetSection;
00079 mTargetSectionLoader = aTransitionInfo.TargetSectionLoader;
00080 mDoLoadTargetSection = aTransitionInfo.DoLoadTargetSection;
00081 mSectionPathRest = aTransitionInfo.SectionPathRest;
00082
00083 mTargetSectionInitializedTask = new FictiveTask();
00084
00085 mPreOpenProgressMonitor = new ProgressMonitor();
00086 mOpenTargetSectionPreconditions = new PreconditionsTask();
00087
00088 mDisposePreconditions = new PreconditionsTask();
00089 mDisposePreconditions.add(new EventDescriptor(this, "readyToDispose"));
00090
00091 Listener.createSingleTimeListener(
00092 new EventDescriptor(mDisposePreconditions, "completed"),
00093 Delegate.create(this, onDisposePreconditionsMet)
00094 );
00095
00096 mOpenTargetSectionPreconditions.add(new EventDescriptor(mPreOpenProgressMonitor, "completed"));
00097
00098 Listener.createSingleTimeListener(
00099 new EventDescriptor(mOpenTargetSectionPreconditions, "completed"),
00100 Delegate.create(this, onOpenTargetSectionPreconditionsMet)
00101 );
00102 }
00103
00104 public function start() : Void
00105 {
00106 mIsRunning = true;
00107 mIsInterrupting = false;
00108
00109 closeCurrentSectionIfNeeded();
00110
00111 if(mDoLoadTargetSection)
00112 {
00113 openLazySection();
00114 }
00115 else
00116 {
00117 openInitializedSection();
00118 }
00119 }
00120
00121 private function closeCurrentSectionIfNeeded() : Void
00122 {
00123 if(mCurrentSection && !mCurrentSection.IsClosed)
00124 {
00125 closeCurrentSection();
00126 }
00127 }
00128
00129 private function closeCurrentSection() : Void
00130 {
00131 mOpenTargetSectionPreconditions.add(new EventDescriptor(mCurrentSection, "closed"));
00132
00133 Listener.createSingleTimeListener(
00134 new EventDescriptor(mCurrentSection, "closed"),
00135 Delegate.create(this, onCurrentSectionClosed)
00136 );
00137
00138 if(!mCurrentSection.IsClosing)
00139 {
00140 triggerCurrentSectionClose();
00141 }
00142 }
00143
00144 public function isRunning() : Boolean
00145 {
00146 return mIsRunning || mChildSectionsTransition.isRunning();
00147 }
00148
00149 public function isInterrupting() : Boolean
00150 {
00151 return mIsInterrupting || mChildSectionsTransition.isInterrupting();
00152 }
00153
00154 public function canInterrupt() : Boolean
00155 {
00156 return true && (!mChildSectionsTransition || mChildSectionsTransition.canInterrupt());
00157 }
00158
00159 public function isImmediatelyInterruptable() : Boolean
00160 {
00161 var result =
00162 (!mChildSectionsTransition || (mChildSectionsTransition && mChildSectionsTransition.isImmediatelyInterruptable())) &&
00163
00164 (!mTargetSection.IsInitializing || (mTargetSection.IsInitializing && mTargetSection.isInitializationImmediatelyInterruptable())) &&
00165 (!mTargetSection.IsActivating || (mTargetSection.IsActivating && mTargetSection.isActivationImmediatelyInterruptable())) &&
00166 (!mTargetSection.IsOpening || (mTargetSection.IsOpening && mTargetSection.isOpeningImmediatelyInterruptable()));
00167
00168 return result;
00169 }
00170
00171 public function interrupt() : Void
00172 {
00173 mIsInterrupting = true;
00174
00175
00176 mOpenTargetSectionPreconditions.interrupt();
00177
00178 var interuptedPreconditions : PreconditionsTask = new PreconditionsTask();
00179 var newCurrentSection : Section = getNewCurrentSectionAfterInterruption();
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 if(mTargetSection && mTargetSection.IsInitializing)
00193 {
00194 interuptedPreconditions.add(new EventDescriptor(mCurrentSection, "initializationInterrupted"));
00195 mTargetSection.interruptInitialization();
00196 }
00197
00198 if(mTargetSection && mTargetSection.IsActivating)
00199 {
00200 interuptedPreconditions.add(new EventDescriptor(mTargetSection, "activationInterrupted"));
00201 mTargetSection.interruptActivation();
00202 }
00203
00204 if(mTargetSection && mTargetSection.IsOpening)
00205 {
00206 interuptedPreconditions.add(new EventDescriptor(mTargetSection, "openInterrupted"));
00207 mTargetSection.interruptOpen();
00208 }
00209
00210 if(mChildSectionsTransition && mChildSectionsTransition.isRunning())
00211 {
00212 interuptedPreconditions.add(new EventDescriptor(mChildSectionsTransition, "interrupted"));
00213 mChildSectionsTransition.interrupt();
00214 }
00215
00216 Listener.createSingleTimeMergingListener(
00217 new EventDescriptor(interuptedPreconditions, "completed"),
00218 Delegate.create(this, onInterrupted),
00219 {newCurrentSection: newCurrentSection}
00220 );
00221
00222 interuptedPreconditions.start();
00223
00224 if(!mDisposePreconditions.isRunning())
00225 {
00226 mDisposePreconditions.start();
00227 }
00228 }
00229
00230 private function getNewCurrentSectionAfterInterruption() : Section
00231 {
00232 var result : Section = mCurrentSection;
00233
00234 if(mTargetSection.IsOpening)
00235 {
00236 result = mTargetSection;
00237 }
00238
00239 return result;
00240 }
00241
00242 private function onInterrupted(ev) : Void
00243 {
00244 mIsInterrupting = false;
00245 mIsRunning = false;
00246
00247 dispatchEvent({type: "interrupted", target: this, newCurrentSection: ev.newCurrentSection});
00248 dispatchEvent({type: "readyToDispose", target: this});
00249 }
00250
00251 private function triggerTargetSectionActivate() : Void
00252 {
00253 if(mIsRunning && !mIsInterrupting)
00254 {
00255 dispatchEvent({type: "targetSectionActivate", target: this});
00256 mTargetSection.activate();
00257 }
00258 }
00259
00260 private function triggerTargetSectionOpen() : Void
00261 {
00262 dispatchEvent({type: "sectionsSwapped", target: this});
00263
00264 if(mIsRunning && !mIsInterrupting)
00265 {
00266 dispatchEvent({type: "targetSectionOpen", target: this});
00267 mTargetSection.open();
00268 }
00269 }
00270
00271 private function triggerCurrentSectionClose() : Void
00272 {
00273
00274 if(mIsRunning && !mIsInterrupting)
00275 {
00276 dispatchEvent({type: "currentSectionClose", target: this});
00277 mCurrentSection.close();
00278 }
00279 }
00280
00281 private function triggerCurrentSectionDestroy() : Void
00282 {
00283
00284
00285
00286 dispatchEvent({type: "currentSectionDestroy", target: this});
00287 mCurrentSection.destroy();
00288 }
00289
00290 private function triggerSectionsControllerOpenSection(aSectionsController : ISectionsController,
00291 aSectionPath : String) : SectionsTransition
00292 {
00293
00294
00295 mChildSectionsTransition = aSectionsController.openSection(aSectionPath);
00296 return mChildSectionsTransition;
00297 }
00298
00299 private function openLazySection() : Void
00300 {
00301 Listener.createSingleTimeListener(
00302 new EventDescriptor(mTargetSectionLoader, "sectionAvailable"),
00303 Delegate.create(this, onLazyTargetSectionAvailable)
00304 );
00305
00306 Listener.createSingleTimeListener(
00307 new EventDescriptor(mTargetSectionLoader, "sectionUIInitialized"),
00308 Delegate.create(this, onLazyTargetSectionUIInitialized)
00309 );
00310
00311 Listener.createSingleTimeListener(
00312 new EventDescriptor(mTargetSectionLoader, "sectionInitialized"),
00313 Delegate.create(this, onLazyTargetSectionInitialized)
00314 );
00315
00316 if(mTargetSectionLoader instanceof SectionLoader)
00317 {
00318 openLazyLoadSection();
00319 }
00320 else if(mTargetSectionLoader instanceof SectionAttacher)
00321 {
00322 openLazyAttachSection();
00323 }
00324 }
00325
00326 private function openLazyLoadSection() : Void
00327 {
00328 mPreOpenProgressMonitor.addFixedPartItem(mTargetSectionInitializedTask, 0);
00329
00330 var targetSectionLoader : SectionLoader = SectionLoader(mTargetSectionLoader);
00331 mPreOpenProgressMonitor.addItem(targetSectionLoader);
00332
00333 mTargetSectionLoader.start();
00334 }
00335
00336 private function openLazyAttachSection() : Void
00337 {
00338 mPreOpenProgressMonitor.addFixedPartItem(mTargetSectionInitializedTask, 0);
00339
00340 mTargetSectionLoader.start();
00341 }
00342
00343 private function openInitializedSection() : Void
00344 {
00345 getAndMonitorTargetSectionPreOpenProgress();
00346 triggerTargetSectionActivate();
00347
00348 openAndMonitorTargetSubSection();
00349
00350 startMonitoringPreOpenProgress();
00351 startMonitoringOpenTargetSectionPreconditions();
00352 }
00353
00354 private function onLazyTargetSectionAvailable(ev) : Void
00355 {
00356 mTargetSection = ev.section;
00357 dispatchEvent({type: "lazyTargetSectionAvailable", target: this, section: ev.section});
00358 }
00359
00360 private function onLazyTargetSectionUIInitialized(ev) : Void
00361 {
00362 dispatchEvent({type: "lazyTargetSectionUIInitialized", target: this, section: ev.section});
00363
00364 getAndMonitorTargetSectionPreOpenProgress();
00365 startMonitoringPreOpenProgress();
00366 }
00367
00368 private function onLazyTargetSectionInitialized(ev) : Void
00369 {
00370 dispatchEvent({type: "lazyTargetSectionInitialized", target: this, section: ev.section});
00371 triggerTargetSectionActivate();
00372
00373 openAndMonitorTargetSubSection();
00374 startMonitoringOpenTargetSectionPreconditions();
00375
00376 mTargetSectionInitializedTask.start();
00377 }
00378
00379 private function startMonitoringOpenTargetSectionPreconditions() : Void
00380 {
00381 mOpenTargetSectionPreconditions.start();
00382 }
00383
00384 private function startMonitoringPreOpenProgress() : Void
00385 {
00386 mPreOpenProgressMonitor.start();
00387 }
00388
00389 private function getAndMonitorTargetSectionPreOpenProgress() : Void
00390 {
00391 var sectionPreOpenProgressMonitoringTask : IProgressiveTask = mTargetSection.getPreOpenProgressMonitoringTask();
00392
00393 if(sectionPreOpenProgressMonitoringTask)
00394 {
00395 monitorTargetSectionPreOpenProgress(sectionPreOpenProgressMonitoringTask);
00396 }
00397 }
00398
00399 private function monitorTargetSectionPreOpenProgress(aSectionPreOpenProgressMonitoringTask : IProgressiveTask) : Void
00400 {
00401 mPreOpenProgressMonitor.addItem(aSectionPreOpenProgressMonitoringTask);
00402 }
00403
00404 private function openAndMonitorTargetSubSection() : Void
00405 {
00406 if((mTargetSection instanceof ISectionsController) && (mSectionPathRest != "" && mSectionPathRest != null && mSectionPathRest != undefined))
00407 {
00408 var childSectionsTransition : SectionsTransition =
00409 triggerSectionsControllerOpenSection(ISectionsController(mTargetSection), mSectionPathRest);
00410
00411 if(childSectionsTransition)
00412 {
00413 monitorSubTransition(childSectionsTransition);
00414 mDisposePreconditions.add(new EventDescriptor(childSectionsTransition, "disposed"));
00415 }
00416 }
00417
00418 mDisposePreconditions.start();
00419 }
00420
00421 private function monitorSubTransition(aSubTransition:SectionsTransition) : Void
00422 {
00423 monitorSubTransitionPreOpenProgress(aSubTransition.PreOpenProgressMonitor);
00424 }
00425
00426 private function monitorSubTransitionPreOpenProgress(aChildSectionsPreOpenMonitor:IProgressiveTask) : Void
00427 {
00428 mPreOpenProgressMonitor.addItem(aChildSectionsPreOpenMonitor);
00429 }
00430
00431 public function addOpenTargetSectionPrecondition(aEventDescriptor:EventDescriptor) : Void
00432 {
00433 mOpenTargetSectionPreconditions.add(aEventDescriptor);
00434 }
00435
00436 private function onOpenTargetSectionPreconditionsMet(ev) : Void
00437 {
00438 Listener.createSingleTimeListener(
00439 new EventDescriptor(mTargetSection, "opened"),
00440 Delegate.create(this, onTargetSectionOpened)
00441 );
00442
00443 triggerTargetSectionOpen();
00444 }
00445
00446 private function onCurrentSectionClosed(ev) : Void
00447 {
00448 if(mDetachCurrentSectionAfterClose)
00449 {
00450 Listener.createSingleTimeListener(
00451 new EventDescriptor(mCurrentSection, "destroyed"),
00452 Delegate.create(this, onCurrentSectionDestroyed)
00453 );
00454
00455 mDisposePreconditions.add(
00456 new EventDescriptor(this, "currentSectionDestroyed"));
00457
00458
00459 DoLaterUtil.doLater(this, triggerCurrentSectionDestroy, null, 1);
00460 }
00461 }
00462
00463 private function onCurrentSectionDestroyed(ev) : Void
00464 {
00465 dispatchEvent({type: "currentSectionDestroyed", target: this, section : mCurrentSection});
00466 }
00467
00468 private function onTargetSectionOpened(ev) : Void
00469 {
00470 completed();
00471 }
00472
00473 private function completed() : Void
00474 {
00475 mIsRunning = false;
00476 mIsInterrupting = false;
00477
00478 dispatchEvent({type: "completed", target: this});
00479
00480
00481 dispatchEvent({type: "readyToDispose", target: this});
00482 }
00483
00484 private function onDisposePreconditionsMet() : Void
00485 {
00486
00487 DoLaterUtil.doLater(this, dispose, null, 1);
00488 }
00489
00490 private function dispose() : Void
00491 {
00492 dispatchEvent({type: "disposed", target: this});
00493 removeAllEventListeners();
00494 }
00495 }