/// <summary> /// Main loop of this worker class. Enumerates any work placed into the work queue. /// </summary> private void EnumerationLoop() { while (bShouldProcessWork) { if (ActiveEnumerationThreads.Count > 0) { // Clear out finished threads List <Thread> FinishedThreads = new List <Thread>(); foreach (Thread t in ActiveEnumerationThreads) { if (!t.IsAlive) { FinishedThreads.Add(t); } } foreach (Thread t in FinishedThreads) { ActiveEnumerationThreads.Remove(t); } } if (bArePackageGroupsLoaded && WorkQueue.Count > 0) { // If there's room for more threads, get the first work order and start a new one if (ActiveEnumerationThreads.Count < this.MaxEnumerationThreadCount) { // Grab the first item in the queue. ItemReference targetReference = WorkQueue.First(); Thread t = new Thread(EnumerateFilesAndFolders); this.ActiveEnumerationThreads.Add(t); t.Start(targetReference); WorkQueue.Remove(targetReference); } } } }
/// <summary> /// Enumerates the files and subfolders in the specified package, starting at /// the provided root path. /// </summary> /// <param name="parentReferenceObject">Parent reference where the search should start.</param> protected void EnumerateFilesAndFolders(object parentReferenceObject) { ItemReference parentReference = parentReferenceObject as ItemReference; if (parentReference != null) { VirtualItemReference virtualParentReference = parentReference as VirtualItemReference; if (virtualParentReference != null) { EnumerateHardReference(virtualParentReference.HardReference); for (int i = 0; i < virtualParentReference.OverriddenHardReferences.Count; ++i) { EnumerateHardReference(virtualParentReference.OverriddenHardReferences[i]); } virtualParentReference.State = ReferenceState.Enumerated; } else { EnumerateHardReference(parentReference); } } }
/// <summary> /// Initializes a new instance of the <see cref="Everlook.Explorer.ItemEnumeratedEventArgs"/> class. /// </summary> /// <param name="InItem">In item.</param> public ItemEnumeratedEventArgs(ItemReference InItem) { this.Item = InItem; }
/// <summary> /// Enumerates a hard reference. /// </summary> /// <param name="hardReference">Hard reference.</param> protected void EnumerateHardReference(ItemReference hardReference) { List <ItemReference> localEnumeratedReferences = new List <ItemReference>(); List <string> packageListFile; if (hardReference.PackageGroup.PackageListfiles.TryGetValue(hardReference.PackageName, out packageListFile)) { IEnumerable <string> strippedListfile = packageListFile.Where(s => s.StartsWith(hardReference.ItemPath, true, new CultureInfo("en-GB"))); foreach (string FilePath in strippedListfile) { string childPath = Regex.Replace(FilePath, "^(?-i)" + Regex.Escape(hardReference.ItemPath), ""); int slashIndex = childPath.IndexOf('\\'); string topDirectory = childPath.Substring(0, slashIndex + 1); if (!String.IsNullOrEmpty(topDirectory)) { ItemReference directoryReference = new ItemReference(hardReference.PackageGroup, hardReference, topDirectory); if (!hardReference.ChildReferences.Contains(directoryReference)) { hardReference.ChildReferences.Add(directoryReference); localEnumeratedReferences.Add(directoryReference); } } else if (String.IsNullOrEmpty(topDirectory) && slashIndex == -1) { ItemReference fileReference = new ItemReference(hardReference.PackageGroup, hardReference, childPath); if (!hardReference.ChildReferences.Contains(fileReference)) { // Files can't have any children, so it will always be enumerated. hardReference.State = ReferenceState.Enumerated; hardReference.ChildReferences.Add(fileReference); localEnumeratedReferences.Add(fileReference); } } else { break; } } lock (EnumeratedReferenceQueueLock) { // Add this directory's enumerated files in order as one block this.EnumeratedReferences.AddRange(localEnumeratedReferences); } hardReference.State = ReferenceState.Enumerated; EnumerationFinishedArgs = new ItemEnumeratedEventArgs(hardReference); RaiseEnumerationFinished(); } else { throw new InvalidDataException("No listfile was found for the package referenced by this item reference."); } }
/// <summary> /// Loads all packages in the currently selected game directory. This function does not enumerate files /// and directories deeper than one to keep the UI responsive. /// </summary> protected void Reload_Implementation() { if (HasPackageDirectoryChanged()) { CachedPackageDirectories = GamePathStorage.Instance.GamePaths; this.PackageGroups.Clear(); if (CachedPackageDirectories.Count > 0) { WorkQueue.Clear(); PackageItemNodeMapping.Clear(); PackageNodeItemMapping.Clear(); PackageGroupVirtualNodeMapping.Clear(); VirtualReferenceMappings.Clear(); } foreach (string packageDirectory in CachedPackageDirectories) { if (Directory.Exists(packageDirectory)) { // Create the package group and add it to the available ones string FolderName = Path.GetFileName(packageDirectory); PackageGroup Group = new PackageGroup(FolderName, packageDirectory); // TODO: Creating a package group is real slow. Speed it up this.PackageGroups.Add(FolderName, Group); // Create a virtual item reference that points to the package group VirtualItemReference packageGroupReference = new VirtualItemReference(Group, new ItemReference(Group)); packageGroupReference.State = ReferenceState.Enumerated; // Create a virtual package folder for the individual packages under the package group ItemReference packageGroupPackagesFolderReference = new ItemReference(Group, packageGroupReference, ""); // Add the package folder as a child to the package group node packageGroupReference.ChildReferences.Add(packageGroupPackagesFolderReference); // Send the package group node to the UI this.PackageGroupAddedArgs = new ItemEnumeratedEventArgs(packageGroupReference); RaisePackageGroupAdded(); // Add the packages in the package group as nodes to the package folder foreach (KeyValuePair <string, List <string> > PackageListfile in Group.PackageListfiles) { if (PackageListfile.Value != null) { string PackageName = Path.GetFileName(PackageListfile.Key); ItemReference packageReference = new ItemReference(Group, packageGroupPackagesFolderReference, PackageName, ""); // Send the package node to the UI this.PackageEnumeratedArgs = new ItemEnumeratedEventArgs(packageReference); RaisePackageEnumerated(); // Submit the package as a work order, enumerating the topmost directories SubmitWork(packageReference); } } } } bIsReloading = false; bArePackageGroupsLoaded = true; } }
/// <summary> /// Initializes a new instance of the <see cref="Everlook.Explorer.VirtualItemReference"/> class, /// where the reference has a parent <see cref="Everlook.Explorer.VirtualItemReference"/>. /// </summary> /// <param name="parentVirtualReference">Parent virtual reference.</param> /// <param name="inPackageGroup">In group.</param> /// <param name="inHardReference">In hard reference.</param> public VirtualItemReference(VirtualItemReference parentVirtualReference, PackageGroup inPackageGroup, ItemReference inHardReference) : this(inPackageGroup, inHardReference) { this.ParentReference = parentVirtualReference; }