using JetBrains.Annotations; using System; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Runtime.CompilerServices; namespace Microsoft.Win32.TaskScheduler { /// Provides information and control for a collection of folders that contain tasks. public sealed class TaskFolderCollection : ICollection, IDisposable, INotifyCollectionChanged, INotifyPropertyChanged { private const string IndexerName = "Item[]"; private readonly TaskFolder parent; private readonly TaskFolder[] v1FolderList; private readonly V2Interop.ITaskFolderCollection v2FolderList; internal TaskFolderCollection() => v1FolderList = new TaskFolder[0]; internal TaskFolderCollection([NotNull] TaskFolder folder, [NotNull] V2Interop.ITaskFolderCollection iCollection) { parent = folder; v2FolderList = iCollection; } /// Occurs when a collection changes. public event NotifyCollectionChangedEventHandler CollectionChanged; /// Occurs when a property value changes. public event PropertyChangedEventHandler PropertyChanged; /// Gets the number of items in the collection. public int Count => v2FolderList?.Count ?? v1FolderList.Length; /// Gets a value indicating whether the is read-only. bool ICollection.IsReadOnly => false; /// Gets the specified folder from the collection. /// The index of the folder to be retrieved. /// A TaskFolder instance that represents the requested folder. public TaskFolder this[int index] { get { if (v2FolderList != null) return new TaskFolder(parent.TaskService, v2FolderList[++index]); return v1FolderList[index]; } } /// Gets the specified folder from the collection. /// The path of the folder to be retrieved. /// A TaskFolder instance that represents the requested folder. public TaskFolder this[[NotNull] string path] { get { try { if (v2FolderList != null) return parent.GetFolder(path); if (v1FolderList != null && v1FolderList.Length > 0 && (path == string.Empty || path == "\\")) return v1FolderList[0]; } catch { } throw new ArgumentException(@"Path not found", nameof(path)); } } /// Adds an item to the . /// The object to add to the . /// /// This action is technically unfeasible due to limitations of the underlying library. Use the instead. /// public void Add([NotNull] TaskFolder item) => throw new NotImplementedException(); /// Removes all items from the . public void Clear() { if (v2FolderList != null) { for (var i = v2FolderList.Count; i > 0; i--) parent.DeleteFolder(v2FolderList[i].Name, false); OnNotifyPropertyChanged(nameof(Count)); OnNotifyPropertyChanged(IndexerName); CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } } /// Determines whether the contains a specific value. /// The object to locate in the . /// true if is found in the ; otherwise, false. public bool Contains([NotNull] TaskFolder item) { if (v2FolderList != null) { for (var i = v2FolderList.Count; i > 0; i--) if (string.Equals(item.Path, v2FolderList[i].Path, StringComparison.CurrentCultureIgnoreCase)) return true; } else return item.Path == "\\"; return false; } /// Copies the elements of the ICollection to an Array, starting at a particular Array index. /// /// The one-dimensional Array that is the destination of the elements copied from . The Array must have /// zero-based indexing. /// /// The zero-based index in array at which copying begins. public void CopyTo(TaskFolder[] array, int arrayIndex) { if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex)); if (array == null) throw new ArgumentNullException(nameof(array)); if (v2FolderList != null) { if (arrayIndex + Count > array.Length) throw new ArgumentException(); foreach (var f in this) array[arrayIndex++] = f; } else { if (arrayIndex + v1FolderList.Length > array.Length) throw new ArgumentException(); v1FolderList.CopyTo(array, arrayIndex); } } /// Releases all resources used by this class. public void Dispose() { if (v1FolderList != null && v1FolderList.Length > 0) { v1FolderList[0].Dispose(); v1FolderList[0] = null; } if (v2FolderList != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(v2FolderList); } /// Determines whether the specified folder exists. /// The path of the folder. /// true if folder exists; otherwise, false. public bool Exists([NotNull] string path) { try { parent.GetFolder(path); return true; } catch { } return false; } /// Gets a list of items in a collection. /// Enumerated list of items in the collection. public IEnumerator GetEnumerator() { if (v2FolderList != null) return new System.Runtime.InteropServices.ComEnumerator(() => v2FolderList.Count, (object o) => v2FolderList[o], o => new TaskFolder(parent.TaskService, o)); return Array.AsReadOnly(v1FolderList).GetEnumerator(); } /* /// Returns the index of the TaskFolder within the collection. /// TaskFolder to find. /// Index of the TaskFolder; -1 if not found. public int IndexOf(TaskFolder item) { return IndexOf(item.Path); } /// Returns the index of the TaskFolder within the collection. /// Path to find. /// Index of the TaskFolder; -1 if not found. public int IndexOf(string path) { if (v2FolderList != null) { for (int i = 0; i < v2FolderList.Count; i++) { if (v2FolderList[new System.Runtime.InteropServices.VariantWrapper(i)].Path == path) return i; } return -1; } else return (v1FolderList.Length > 0 && (path == string.Empty || path == "\\")) ? 0 : -1; } */ /// Removes the first occurrence of a specific object from the . /// The object to remove from the . /// /// true if was successfully removed from the ; otherwise, false. This method /// also returns false if is not found in the original . /// public bool Remove([NotNull] TaskFolder item) { if (v2FolderList != null) { for (var i = v2FolderList.Count; i > 0; i--) { if (string.Equals(item.Path, v2FolderList[i].Path, StringComparison.CurrentCultureIgnoreCase)) { try { parent.DeleteFolder(v2FolderList[i].Name); OnNotifyPropertyChanged(nameof(Count)); OnNotifyPropertyChanged(IndexerName); CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, i)); } catch { return false; } return true; } } } return false; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); /// Called when a property has changed to notify any attached elements. /// Name of the property. private void OnNotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }