2007-05-11 21:15:35 +00:00
|
|
|
#region CPL License
|
|
|
|
/*
|
|
|
|
Nuclex Framework
|
2008-01-07 18:04:02 +00:00
|
|
|
Copyright (C) 2002-2008 Nuclex Development Labs
|
2007-05-11 21:15:35 +00:00
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the IBM Common Public License as
|
|
|
|
published by the IBM Corporation; either version 1.0 of the
|
|
|
|
License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
IBM Common Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the IBM Common Public
|
|
|
|
License along with this library
|
|
|
|
*/
|
|
|
|
#endregion
|
2007-07-24 20:15:19 +00:00
|
|
|
|
2007-04-18 20:20:03 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
namespace Nuclex.Support.Tracking {
|
|
|
|
|
|
|
|
/// <summary>Progression being observed by another class</summary>
|
|
|
|
/// <typeparam name="ProgressionType">
|
|
|
|
/// Type of the progression that is being observed
|
|
|
|
/// </typeparam>
|
2008-03-26 21:20:52 +00:00
|
|
|
internal class ObservedWeightedWaitable<ProgressionType> : IDisposable
|
2008-03-26 21:03:49 +00:00
|
|
|
where ProgressionType : Waitable {
|
2007-04-18 20:20:03 +00:00
|
|
|
|
2007-04-19 18:18:34 +00:00
|
|
|
/// <summary>Delegate for reporting progress updates</summary>
|
|
|
|
public delegate void ReportDelegate();
|
|
|
|
|
2007-04-18 20:20:03 +00:00
|
|
|
/// <summary>Initializes a new observed progression</summary>
|
|
|
|
/// <param name="weightedProgression">Weighted progression being observed</param>
|
2007-04-19 18:18:34 +00:00
|
|
|
/// <param name="progressUpdateCallback">
|
|
|
|
/// Callback to invoke when the progression's progress changes
|
|
|
|
/// </param>
|
|
|
|
/// <param name="endedCallback">
|
|
|
|
/// Callback to invoke when the progression has ended
|
|
|
|
/// </param>
|
2008-03-26 21:20:52 +00:00
|
|
|
internal ObservedWeightedWaitable(
|
|
|
|
WeightedWaitable<ProgressionType> weightedProgression,
|
2007-04-19 18:18:34 +00:00
|
|
|
ReportDelegate progressUpdateCallback,
|
|
|
|
ReportDelegate endedCallback
|
2007-04-18 20:20:03 +00:00
|
|
|
) {
|
|
|
|
this.weightedProgression = weightedProgression;
|
2007-04-19 18:18:34 +00:00
|
|
|
|
2008-03-26 19:52:28 +00:00
|
|
|
// See if this progression has already ended (initial check for performance)
|
2008-03-26 21:20:52 +00:00
|
|
|
if(weightedProgression.Waitable.Ended) {
|
2007-04-19 18:18:34 +00:00
|
|
|
|
2007-07-12 22:02:23 +00:00
|
|
|
this.progress = 1.0f;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
this.endedCallback = endedCallback;
|
|
|
|
this.progressUpdateCallback = progressUpdateCallback;
|
|
|
|
|
2008-03-26 21:20:52 +00:00
|
|
|
this.weightedProgression.Waitable.AsyncEnded +=
|
2007-07-12 22:02:23 +00:00
|
|
|
new EventHandler(asyncEnded);
|
|
|
|
|
2008-03-26 19:52:28 +00:00
|
|
|
// Check whether this progression might have ended before we were able to
|
|
|
|
// attach ourselfes to its event. If so, don't bother registering to the
|
|
|
|
// other event and (important) set our progress to 1.0 because, since we
|
|
|
|
// might not have gotten the 'Ended' event, it might otherwise stay at 0.0
|
|
|
|
// even though the progression is in the 'Ended' state.
|
2008-03-26 21:20:52 +00:00
|
|
|
if(weightedProgression.Waitable.Ended) {
|
2008-03-26 19:52:28 +00:00
|
|
|
this.progress = 1.0f;
|
|
|
|
} else {
|
2008-03-26 21:20:52 +00:00
|
|
|
this.progressReporter = this.weightedProgression.Waitable as IProgressReporter;
|
2008-03-26 21:03:49 +00:00
|
|
|
|
|
|
|
if(this.progressReporter != null) {
|
|
|
|
this.asyncProgressChangedEventHandler = new EventHandler<ProgressReportEventArgs>(
|
|
|
|
asyncProgressChanged
|
|
|
|
);
|
|
|
|
|
|
|
|
this.progressReporter.AsyncProgressChanged +=
|
|
|
|
this.asyncProgressChangedEventHandler;
|
|
|
|
}
|
2008-03-26 19:52:28 +00:00
|
|
|
}
|
2007-07-12 22:02:23 +00:00
|
|
|
|
|
|
|
}
|
2007-04-18 20:20:03 +00:00
|
|
|
}
|
2007-04-19 18:18:34 +00:00
|
|
|
|
|
|
|
/// <summary>Immediately releases all resources owned by the object</summary>
|
|
|
|
public void Dispose() {
|
2007-04-20 18:04:19 +00:00
|
|
|
asyncDisconnectEvents();
|
2007-04-19 18:18:34 +00:00
|
|
|
}
|
|
|
|
|
2007-04-18 20:20:03 +00:00
|
|
|
/// <summary>Weighted progression being observed</summary>
|
2008-03-26 21:20:52 +00:00
|
|
|
public WeightedWaitable<ProgressionType> WeightedWaitable {
|
2007-04-18 20:20:03 +00:00
|
|
|
get { return this.weightedProgression; }
|
|
|
|
}
|
|
|
|
|
2007-04-19 18:18:34 +00:00
|
|
|
/// <summary>Amount of progress this progression has achieved so far</summary>
|
|
|
|
public float Progress {
|
|
|
|
get { return this.progress; }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>Called when the observed progression has ended</summary>
|
|
|
|
/// <param name="sender">Progression that has ended</param>
|
|
|
|
/// <param name="e">Not used</param>
|
|
|
|
private void asyncEnded(object sender, EventArgs e) {
|
2007-04-20 18:04:19 +00:00
|
|
|
ReportDelegate endedCallback = this.endedCallback;
|
|
|
|
ReportDelegate progressUpdateCallback = this.progressUpdateCallback;
|
2007-04-19 18:18:34 +00:00
|
|
|
|
2007-04-20 18:04:19 +00:00
|
|
|
asyncDisconnectEvents(); // We don't need those anymore!
|
2007-04-19 18:18:34 +00:00
|
|
|
|
2007-06-12 19:15:55 +00:00
|
|
|
// If the progress hasn't reached 1.0 yet, make a fake report so that even
|
2007-07-09 21:41:21 +00:00
|
|
|
// when a progression doesn't report any progress at all, the set or queue
|
2007-06-12 19:15:55 +00:00
|
|
|
// owning us will have a percentage of progressions completed.
|
|
|
|
//
|
|
|
|
// There is the possibility of a race condition here, as a final progress
|
2007-07-09 21:41:21 +00:00
|
|
|
// report could have been generated by a thread running the progression
|
|
|
|
// that was preempted by this thread. This would cause the progress to
|
|
|
|
// jump to 1.0 and then back to whatever the waiting thread will report.
|
2007-05-08 18:42:00 +00:00
|
|
|
if(this.progress != 1.0f) {
|
|
|
|
this.progress = 1.0f;
|
|
|
|
progressUpdateCallback();
|
|
|
|
}
|
2007-04-20 18:04:19 +00:00
|
|
|
|
|
|
|
endedCallback();
|
2007-04-19 18:18:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>Called when the progress of the observed progression changes</summary>
|
|
|
|
/// <param name="sender">Progression whose progress has changed</param>
|
|
|
|
/// <param name="e">Contains the updated progress</param>
|
2008-03-26 21:03:49 +00:00
|
|
|
private void asyncProgressChanged(object sender, ProgressReportEventArgs e) {
|
2007-04-19 18:18:34 +00:00
|
|
|
this.progress = e.Progress;
|
|
|
|
this.progressUpdateCallback();
|
|
|
|
}
|
|
|
|
|
2007-06-12 19:15:55 +00:00
|
|
|
/// <summary>Unsubscribes from all events of the observed progression</summary>
|
2007-04-20 18:04:19 +00:00
|
|
|
private void asyncDisconnectEvents() {
|
2007-04-19 18:18:34 +00:00
|
|
|
|
|
|
|
// Make use of the double check locking idiom to avoid the costly lock when
|
|
|
|
// the events have already been unsubscribed
|
|
|
|
if(this.endedCallback != null) {
|
|
|
|
|
|
|
|
// This is an internal class with special knowledge that there
|
|
|
|
// is no risk of deadlock involved, so we don't need a fancy syncRoot!
|
|
|
|
lock(this) {
|
|
|
|
if(this.endedCallback != null) {
|
2008-03-26 21:20:52 +00:00
|
|
|
this.weightedProgression.Waitable.AsyncEnded -=
|
2007-04-19 18:18:34 +00:00
|
|
|
new EventHandler(asyncEnded);
|
|
|
|
|
2008-03-26 21:03:49 +00:00
|
|
|
if(this.progressReporter != null) {
|
|
|
|
this.progressReporter.AsyncProgressChanged -=
|
|
|
|
this.asyncProgressChangedEventHandler;
|
|
|
|
|
|
|
|
this.asyncProgressChangedEventHandler = null;
|
|
|
|
}
|
2007-04-19 18:18:34 +00:00
|
|
|
|
|
|
|
this.endedCallback = null;
|
|
|
|
this.progressUpdateCallback = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // endedCallback != null
|
|
|
|
|
2007-04-18 20:20:03 +00:00
|
|
|
}
|
2007-04-19 18:18:34 +00:00
|
|
|
|
2008-03-26 21:03:49 +00:00
|
|
|
private EventHandler<ProgressReportEventArgs> asyncProgressChangedEventHandler;
|
|
|
|
/// <summary>The observed progression's progress reporting interface</summary>
|
|
|
|
private IProgressReporter progressReporter;
|
2007-04-18 20:20:03 +00:00
|
|
|
/// <summary>The weighted progression that is being observed</summary>
|
2008-03-26 21:20:52 +00:00
|
|
|
private WeightedWaitable<ProgressionType> weightedProgression;
|
2007-04-19 18:18:34 +00:00
|
|
|
/// <summary>Callback to invoke when the progress updates</summary>
|
|
|
|
private volatile ReportDelegate progressUpdateCallback;
|
|
|
|
/// <summary>Callback to invoke when the progression ends</summary>
|
|
|
|
private volatile ReportDelegate endedCallback;
|
|
|
|
/// <summary>Progress achieved so far</summary>
|
2007-04-18 20:20:03 +00:00
|
|
|
private volatile float progress;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Nuclex.Support.Tracking
|