/* NOTICE OF CHANGES: date of change: 3/11/2009 change: Externalized strings. date of chagne: 3/17/2009 change: Strings in shared component must be externalized to a new project SMSharedStrings */ using System; using System.Collections; using TaskSchedulerInterop; using SMStrings; namespace TaskScheduler { /// /// TriggerList is a collection of Triggers. Every Task has a TriggerList that is /// created and destroyed automatically along with the Task. There are no public constructors. /// /// /// /// A TriggerList can be empty, and indeed a newly created Task has an empty list. /// It's not clear how the system handles a task with no triggers, however. /// /// TriggerList implements IList and behaves like other indexable collections with one limitation: /// You can't insert a Trigger at a position. Insert() throws NotImplementedException. This /// restriction is based on the underlying API. /// public class TriggerList : IList, IDisposable { // Internal COM interface to access task that this list is associated with. private ITask iTask; // Trigger objects store in an ArrayList private ArrayList oTriggers; /// /// Internal constructor creates TriggerList using an ITask interface to initialize. /// /// Instance of an ITask. internal TriggerList(ITask iTask) { this.iTask = iTask; ushort cnt = 0; iTask.GetTriggerCount(out cnt); oTriggers = new ArrayList(cnt+5); //Allow for five additional entries without growing base array for (int i=0; i /// Enumerator for TriggerList; implements IEnumerator interface. /// private class Enumerator : IEnumerator { private TriggerList outer; private int currentIndex; /// /// Internal constructor - Only accessible through . /// /// Instance of a TriggerList. internal Enumerator(TriggerList outer) { this.outer = outer; Reset(); } /// /// Moves to the next trigger. See for more information. /// /// False if there is no next trigger. public bool MoveNext() { return ++currentIndex < outer.oTriggers.Count; } /// /// Reset trigger enumeration. See for more information. /// public void Reset() { currentIndex = -1; } /// /// Retrieves the current trigger. See for more information. /// public object Current { get { return outer.oTriggers[currentIndex]; } } } #region Implementation of IList /// /// Removes the trigger at a specified index. /// /// Index of trigger to remove. /// Index out of range. public void RemoveAt(int index) { if (index >= Count) throw new ArgumentOutOfRangeException("index", index, SMSharedStringTable.GetString("SMSCHEDULER_FAILEDTOREMOVE_10")); ((Trigger)oTriggers[index]).Unbind(); //releases resources in the trigger oTriggers.RemoveAt(index); //Remove the Trigger object from the array representing the list iTask.DeleteTrigger((ushort)index); //Remove the trigger from the Task Scheduler } /// /// Not implemented; throws NotImplementedException. /// If implemented, would insert a trigger at a specified index. /// /// Index to insert trigger. /// Value of trigger to insert. void IList.Insert(int index, object value) { throw new NotImplementedException(SMSharedStringTable.GetString("SMSCHEDULER_TRIGGERLISTDOE_21")); } /// /// Removes the trigger from the collection. If the trigger is not in /// the collection, nothing happens. (No exception.) /// /// Trigger to remove. public void Remove(Trigger trigger) { int i = IndexOf(trigger); if (i != -1) RemoveAt(i); } /// /// IList.Remove implementation. /// void IList.Remove(object value) { Remove(value as Trigger); } /// /// Test to see if trigger is part of the collection. /// /// Trigger to find. /// true if trigger found in collection. public bool Contains(Trigger trigger) { return (IndexOf(trigger) != -1); } /// /// IList.Contains implementation. /// bool IList.Contains(object value) { return Contains(value as Trigger); } /// /// Remove all triggers from collection. /// public void Clear() { for (int i = Count-1; i >= 0; i--) { RemoveAt(i); } } /// /// Returns the index of the supplied Trigger. /// /// Trigger to find. /// Zero based index in collection, -1 if not a member. public int IndexOf(Trigger trigger) { for (int i = 0; i < Count; i++) { if (this[i].Equals(trigger)) return i; } return -1; } /// /// IList.IndexOf implementation. /// int IList.IndexOf(object value) { return IndexOf(value as Trigger); } /// /// Add the supplied Trigger to the collection. The Trigger to be added must be unbound, /// i.e. it must not be a current member of a TriggerList--this or any other. /// /// Trigger to add. /// Index of added trigger. /// Trigger being added is already bound. public int Add(Trigger trigger) { // if trigger is already bound a list throw an exception if (trigger.Bound) throw new ArgumentException(SMSharedStringTable.GetString("SMSCHEDULER_ATRIGGERCANNOT_5")); // Add a trigger to the task for this TaskList ITaskTrigger iTrigger; ushort index; iTask.CreateTrigger(out index, out iTrigger); // Add the Trigger to the TaskList trigger.Bind(iTrigger); int index2 = oTriggers.Add(trigger); // Verify index is the same in task and in list if (index2 != (int)index) throw new ApplicationException(SMSharedStringTable.GetString("SMSCHEDULER_ASSERTIONFAILU_4")); return (int)index; } /// /// IList.Add implementation. /// int IList.Add(object value) { return Add(value as Trigger); } /// /// Gets read-only state of collection. Always false for TriggerLists. /// public bool IsReadOnly { get { return false; } } /// /// Access the Trigger at a specified index. Assigning to a TriggerList element requires /// the value to unbound. The previous list element becomes unbound and lost, /// while the newly assigned Trigger becomes bound in its place. /// /// Collection index out of range. public Trigger this[int index] { get { if (index >= Count) throw new ArgumentOutOfRangeException("index", index, SMSharedStringTable.GetString("SMSCHEDULER_TRIGGERLISTCOL_23")); return (Trigger)oTriggers[index]; } set { if (index >= Count) throw new ArgumentOutOfRangeException("index", index, SMSharedStringTable.GetString("SMSCHEDULER_TRIGGERLISTCOL_23")); Trigger previous = (Trigger)oTriggers[index]; value.Bind(previous); oTriggers[index] = value; } } /// /// IList.this[int] implementation. /// object IList.this[int index] { get { return this[index]; } set { this[index] = (value as Trigger); } } /// /// Returns whether collection is a fixed size. Always returns false for TriggerLists. /// public bool IsFixedSize { get { return false; } } #endregion #region Implementation of ICollection /// /// Gets the number of Triggers in the collection. /// public int Count { get { return oTriggers.Count; } } /// /// Copies all the Triggers in the collection to an array, beginning at the given index. /// The Triggers assigned to the array are cloned from the originals, implying they are /// unbound copies. (Can't tell if cloning is the intended semantics for this ICollection method, /// but it seems a good choice for TriggerLists.) /// /// Array to copy triggers into. /// Index at which to start copying. public void CopyTo(System.Array array, int index) { if (oTriggers.Count > array.Length - index) { throw new ArgumentException(SMSharedStringTable.GetString("SMSCHEDULER_ARRAYHASINSUFF_3")); } for (int i = 0; i /// Returns synchronizable state. Always false since the Task Scheduler is not /// thread safe. /// public bool IsSynchronized { get { return false; } } /// /// Gets the root object for synchronization. Always null since TriggerLists aren't synchronized. /// public object SyncRoot { get { return null; } } #endregion #region Implementation of IEnumerable /// /// Gets a TriggerList enumerator. /// /// Enumerator for TriggerList. public System.Collections.IEnumerator GetEnumerator() { return new Enumerator(this); } #endregion #region Implementation of IDisposable /// /// Unbinds and Disposes all the Triggers in the collection, releasing the com interfaces they hold. /// Destroys the internal private pointer to the ITask com interface, but does not /// specifically release the interface because it is also in the containing task. /// public void Dispose() { foreach (object o in oTriggers) { ((Trigger)o).Unbind(); } oTriggers = null; iTask = null; } #endregion } }