diff --git a/ApplicationView/ApplicationController.cs b/ApplicationView/ApplicationController.cs index 201da4d6b..cf166e00a 100644 --- a/ApplicationView/ApplicationController.cs +++ b/ApplicationView/ApplicationController.cs @@ -195,8 +195,7 @@ namespace MatterHackers.MatterControl { lock(thumbsLock) { - if (thumbnailGenerator == null - || thumbnailGenerator.IsCompleted) + if (thumbnailGenerator == null) { // Spin up a new thread once needed thumbnailGenerator = Task.Run((Action)ThumbGeneration); @@ -211,7 +210,7 @@ namespace MatterHackers.MatterControl { Thread.CurrentThread.Name = $"ThumbnailGeneration"; - while(!MatterControlApplication.Instance.HasBeenClosed) + while(!MatterControlApplication.Instance.ApplicationExiting) { Thread.Sleep(100); @@ -235,13 +234,16 @@ namespace MatterHackers.MatterControl } catch (ThreadAbortException e) { - return; + Console.WriteLine("ThumbGeneration Thread abort"); } catch (Exception ex) { Console.WriteLine("Error generating thumbnail: " + ex.Message); } } + + // Null task reference on exit + thumbnailGenerator = null; } public static Func> GetPrinterProfileAsync; @@ -343,20 +345,18 @@ namespace MatterHackers.MatterControl var rootLibraryCollection = Datastore.Instance.dbSQLite.Table().Where(v => v.Name == "_library").Take(1).FirstOrDefault(); if (rootLibraryCollection != null) { - int rooteLibraryID = rootLibraryCollection.Id; - this.Library.RegisterRootProvider( new DynamicContainerLink( "Local Library".Localize(), LibraryProviderHelpers.LoadInvertIcon("FileDialog", "library_folder.png"), - () => new SqliteLibraryContainer(rooteLibraryID))); + () => new SqliteLibraryContainer(rootLibraryCollection.Id))); } this.Library.RegisterRootProvider( new DynamicContainerLink( "Print History".Localize(), LibraryProviderHelpers.LoadInvertIcon("FileDialog", "folder.png"), - () => new HistoryContainer()) + () => new PrintHistoryContainer()) { IsReadOnly = true }); @@ -478,6 +478,14 @@ namespace MatterHackers.MatterControl }, ref unregisterEvents); } + internal void Shutdown() + { + // Ensure all threads shutdown gracefully on close + + // Release any waiting generator threads + thumbGenResetEvent?.Set(); + } + public void StartSignIn() { if (this.ActivePrinter.Connection.PrinterIsPrinting @@ -619,7 +627,7 @@ namespace MatterHackers.MatterControl }, "Are you sure you want to sign out? You will not have access to your printer profiles or cloud library.".Localize(), "Sign Out?".Localize(), StyledMessageBox.MessageType.YES_NO, "Sign Out".Localize(), "Cancel".Localize()); } else // just run the sign out event - { + { SignOutAction?.Invoke(); } } @@ -823,7 +831,6 @@ namespace MatterHackers.MatterControl } } - if (this.ActivePrinter.Settings.PrinterSelected && this.ActivePrinter.Settings.GetValue(SettingsKey.auto_connect)) { diff --git a/History/PrintHistoryListItem.cs b/History/PrintHistoryListItem.cs index a0b721a95..412684e69 100644 --- a/History/PrintHistoryListItem.cs +++ b/History/PrintHistoryListItem.cs @@ -53,7 +53,7 @@ namespace MatterHackers.MatterControl.PrintHistory public ListViewItemBase AddItem(ListViewItem item) { - var historyRowItem = item.Model as HistoryRowItem; + var historyRowItem = item.Model as PrintHistoryItem; var detailsView = new PrintHistoryListItem(item, this.ThumbWidth, this.ThumbHeight, historyRowItem?.PrintTask, true); this.AddChild(detailsView); diff --git a/Library/ExtensionMethods.cs b/Library/ExtensionMethods.cs index 3586d65cd..2b81536b3 100644 --- a/Library/ExtensionMethods.cs +++ b/Library/ExtensionMethods.cs @@ -49,11 +49,6 @@ namespace MatterHackers.MatterControl.Library } } - public static void AddItem(this ILibraryContainer container, PrintItemWrapper printeItemWrapper) - { - throw new NotImplementedException("container.AddItem(PrintItemWrapper)"); - } - public static void Add(this Dictionary list, IEnumerable extensions, IContentProvider provider) { foreach (var extension in extensions) diff --git a/Library/Interfaces/ILibraryContainer.cs b/Library/Interfaces/ILibraryContainer.cs index a49cc167a..6cac49ee8 100644 --- a/Library/Interfaces/ILibraryContainer.cs +++ b/Library/Interfaces/ILibraryContainer.cs @@ -44,7 +44,7 @@ namespace MatterHackers.MatterControl.Library Type DefaultView { get; } - event EventHandler Reloaded; + event EventHandler ContentChanged; List ChildContainers { get; } List Items { get; } @@ -55,6 +55,7 @@ namespace MatterHackers.MatterControl.Library void Deactivate(); void Activate(); + void Load(); } public interface ILibraryWritableContainer : ILibraryContainer diff --git a/Library/Providers/FileSystem/FileSystemContainer.cs b/Library/Providers/FileSystem/FileSystemContainer.cs index 7713e3465..12fde2c70 100644 --- a/Library/Providers/FileSystem/FileSystemContainer.cs +++ b/Library/Providers/FileSystem/FileSystemContainer.cs @@ -72,7 +72,6 @@ namespace MatterHackers.MatterControl.Library directoryWatcher.EnableRaisingEvents = true; } #endif - GetFilesAndCollectionsInCurrentDirectory(); } // Indicates if the new AMF file should use the original file name incremented until no name collision occurs @@ -81,12 +80,6 @@ namespace MatterHackers.MatterControl.Library public override void Activate() { this.isActiveContainer = true; - - if (isDirty) - { - // Requires reload - GetFilesAndCollectionsInCurrentDirectory(); - } base.Activate(); } @@ -109,11 +102,6 @@ namespace MatterHackers.MatterControl.Library if (keywordFilter != value) { keywordFilter = value; - - if (isActiveContainer) - { - GetFilesAndCollectionsInCurrentDirectory(true); - } } } } @@ -139,66 +127,63 @@ namespace MatterHackers.MatterControl.Library // Only refresh content if we're the active container if (isActiveContainer) { - GetFilesAndCollectionsInCurrentDirectory(); + this.Load(false); } } - private async void GetFilesAndCollectionsInCurrentDirectory(bool recursive = false) + public override void Load() + { + this.Load(false); + } + + public void Load(bool recursive) { SearchOption searchDepth = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; - await Task.Run(() => + try { - try + string filter = this.KeywordFilter.Trim(); + + var allFiles = Directory.GetFiles(fullPath, "*.*", searchDepth); + + var zipFiles = allFiles.Where(f => Path.GetExtension(f).IndexOf(".zip", StringComparison.OrdinalIgnoreCase) != -1); + + var nonZipFiles = allFiles.Except(zipFiles); + + List containers; + if (filter == "") { - string filter = this.KeywordFilter.Trim(); - - var allFiles = Directory.GetFiles(fullPath, "*.*", searchDepth); - - var zipFiles = allFiles.Where(f => Path.GetExtension(f).IndexOf(".zip", StringComparison.OrdinalIgnoreCase) != -1); - - var nonZipFiles = allFiles.Except(zipFiles); - - List containers; - if (filter == "") - { - var directories = Directory.GetDirectories(fullPath, "*.*", searchDepth).Select(p => new DirectoryContainerLink(p)).ToList(); - containers = directories.Concat(zipFiles.Select(f => new LocalZipContainerLink(f))).OrderBy(d => d.Name).ToList(); - } - else - { - containers = new List(); - } - - var matchedFiles = (filter == "") ? nonZipFiles : nonZipFiles.Where(filePath => - { - string fileName = Path.GetFileName(filePath); - return FileNameContainsFilter(filePath, filter) - && ApplicationController.Instance.Library.IsContentFileType(fileName); - }); - - UiThread.RunOnIdle(() => - { - // Matched containers - this.ChildContainers = containers; - - // Matched files projected onto FileSystemFileItem - this.Items = matchedFiles.OrderBy(f => f).Select(f => new FileSystemFileItem(f)).ToList(); - - this.isDirty = false; - - this.OnReloaded(); - }); + var directories = Directory.GetDirectories(fullPath, "*.*", searchDepth).Select(p => new DirectoryContainerLink(p)).ToList(); + containers = directories.Concat(zipFiles.Select(f => new LocalZipContainerLink(f))).OrderBy(d => d.Name).ToList(); } - catch (Exception ex) + else { - this.ChildContainers = new List(); - this.Items = new List() - { - new MessageItem("Error loading container - " + ex.Message) - }; + containers = new List(); } - }); + + var matchedFiles = (filter == "") ? nonZipFiles : nonZipFiles.Where(filePath => + { + string fileName = Path.GetFileName(filePath); + return FileNameContainsFilter(filePath, filter) + && ApplicationController.Instance.Library.IsContentFileType(fileName); + }); + + // Matched containers + this.ChildContainers = containers; + + // Matched files projected onto FileSystemFileItem + this.Items = matchedFiles.OrderBy(f => f).Select(f => new FileSystemFileItem(f)).ToList(); + + this.isDirty = false; + } + catch (Exception ex) + { + this.ChildContainers = new List(); + this.Items = new List() + { + new MessageItem("Error loading container - " + ex.Message) + }; + } } private bool FileNameContainsFilter(string filename, string filter) @@ -217,8 +202,6 @@ namespace MatterHackers.MatterControl.Library return true; } - #region Container Actions - private string GetNonCollidingName(string fileName) { string incrementedFilePath; @@ -241,7 +224,7 @@ namespace MatterHackers.MatterControl.Library incrementedFilePath = Path.Combine(this.fullPath, $"{fileName} ({foundCount++}){fileExtension}"); // Continue incrementing while any matching file exists - } while (Directory.GetFiles(incrementedFilePath).Any()); + } while (File.Exists(incrementedFilePath)); return incrementedFilePath; } @@ -307,10 +290,9 @@ namespace MatterHackers.MatterControl.Library if (this.isDirty) { - this.GetFilesAndCollectionsInCurrentDirectory(); + this.OnContentChanged(); } } - public override void Remove(IEnumerable items) { @@ -324,12 +306,7 @@ namespace MatterHackers.MatterControl.Library { if (Directory.Exists(directoryLink.Path)) { - //string destPath = Path.Combine(Path.GetDirectoryName(fileSystemContainer.fullPath), revisedName); - //Directory.Move(fileSystemContainer.fullPath, destPath); - - //await Task.Delay(150); - - //GetFilesAndCollectionsInCurrentDirectory(); + Process.Start(this.fullPath); } } else if (item is FileSystemFileItem fileItem) @@ -345,13 +322,11 @@ namespace MatterHackers.MatterControl.Library fileItem.Path = destFile; - this.OnReloaded(); + this.OnContentChanged(); } } } - #endregion - public class DirectoryContainerLink : FileSystemItem, ILibraryContainerLink { public DirectoryContainerLink(string path) diff --git a/Library/Providers/LibraryConfig.cs b/Library/Providers/LibraryConfig.cs index ba7267f27..fc1c0eb32 100644 --- a/Library/Providers/LibraryConfig.cs +++ b/Library/Providers/LibraryConfig.cs @@ -39,7 +39,7 @@ namespace MatterHackers.MatterControl.Library { ILibraryContainer ActiveContainer { get; set; } event EventHandler ContainerChanged; - event EventHandler ContainerReloaded; + event EventHandler ContentChanged; } public class ContainerChangedEventArgs : EventArgs @@ -57,7 +57,7 @@ namespace MatterHackers.MatterControl.Library public class LibraryConfig : ILibraryContext { public event EventHandler ContainerChanged; - public event EventHandler ContainerReloaded; + public event EventHandler ContentChanged; // TODO: Needed? public event EventHandler LibraryItemsChanged; @@ -65,7 +65,7 @@ namespace MatterHackers.MatterControl.Library private List libraryProviders; private ILibraryContainer activeContainer; - + public LibraryConfig() { libraryProviders = new List(); @@ -101,7 +101,7 @@ namespace MatterHackers.MatterControl.Library if (activeContainer != null) { activeContainer.Deactivate(); - activeContainer.Reloaded -= ActiveContainer_Reloaded; + activeContainer.ContentChanged -= ActiveContainer_ContentChanged; activeContainer.KeywordFilter = ""; // If the new container is an ancestor of the active container we need to Dispose everyone up to that point @@ -118,7 +118,7 @@ namespace MatterHackers.MatterControl.Library activeContainer = newContainer; activeContainer.Activate(); - activeContainer.Reloaded += ActiveContainer_Reloaded; + activeContainer.ContentChanged += ActiveContainer_ContentChanged; ContainerChanged?.Invoke(this, eventArgs); } @@ -149,12 +149,6 @@ namespace MatterHackers.MatterControl.Library OnLibraryItemsChanged(); } - public void RegisterCreator(ILibraryContainerLink containerItem) - { - this.RootLibaryContainer.ChildContainers.Add(containerItem); - OnLibraryItemsChanged(); - } - public void RegisterCreator(ILibraryContentItem libraryItem) { this.RootLibaryContainer.Items.Add(libraryItem); @@ -172,14 +166,14 @@ namespace MatterHackers.MatterControl.Library LibraryItemsChanged?.Invoke(this, null); } - private void ActiveContainer_Reloaded(object sender, EventArgs args) + private void ActiveContainer_ContentChanged(object sender, EventArgs args) { this.OnContainerChanged(this.ActiveContainer); } private void OnContainerChanged(ILibraryContainer container) { - ContainerReloaded?.Invoke(this, new ContainerChangedEventArgs(container, null)); + ContentChanged?.Invoke(this, new ContainerChangedEventArgs(container, null)); } public bool IsContentFileType(string fileName) diff --git a/Library/Providers/LibraryContainer.cs b/Library/Providers/LibraryContainer.cs index 73d6beffe..264a5d8e9 100644 --- a/Library/Providers/LibraryContainer.cs +++ b/Library/Providers/LibraryContainer.cs @@ -36,7 +36,7 @@ namespace MatterHackers.MatterControl.Library { public abstract class LibraryContainer : ILibraryContainer { - public event EventHandler Reloaded; + public event EventHandler ContentChanged; public string ID { get; set; } public string Name { get; set; } @@ -59,11 +59,13 @@ namespace MatterHackers.MatterControl.Library public virtual string KeywordFilter { get; set; } = ""; - protected void OnReloaded() + protected void OnContentChanged() { - this.Reloaded?.Invoke(this, null); + this.ContentChanged?.Invoke(this, null); } + public abstract void Load(); + public virtual void Dispose() { } diff --git a/Library/Providers/MatterControl/CalibrationPartsContainer.cs b/Library/Providers/MatterControl/CalibrationPartsContainer.cs index 2e86b412f..38a193c5e 100644 --- a/Library/Providers/MatterControl/CalibrationPartsContainer.cs +++ b/Library/Providers/MatterControl/CalibrationPartsContainer.cs @@ -30,7 +30,6 @@ either expressed or implied, of the FreeBSD Project. using System.Collections.Generic; using System.IO; using System.Linq; -using System.Threading.Tasks; using MatterHackers.Agg.Platform; using MatterHackers.Agg.UI; using MatterHackers.Localizations; @@ -44,43 +43,36 @@ namespace MatterHackers.MatterControl.Library this.ChildContainers = new List(); this.Items = new List(); this.Name = "Calibration Parts".Localize(); - - this.ReloadContainer(); } - private void ReloadContainer() + public override void Load() { - Task.Run(() => + // TODO: Long term do we want to have multiple categories in the view - OEM parts and printer specific calibration parts? Easy to do if so + /* + IEnumerable printerFiles; + + string printerCalibrationFiles = ActiveSliceSettings.Instance.GetValue("calibration_files"); + if (string.IsNullOrEmpty(printerCalibrationFiles)) { - // TODO: Long term do we want to have multiple categories in the view - OEM parts and printer specific calibration parts? Easy to do if so - /* - IEnumerable printerFiles; + return; + } - string printerCalibrationFiles = ActiveSliceSettings.Instance.GetValue("calibration_files"); - if (string.IsNullOrEmpty(printerCalibrationFiles)) - { - return; - } + string[] calibrationPrintFileNames = printerCalibrationFiles.Split(';'); + if (calibrationPrintFileNames.Length < 0) + { + printerFiles = Enumerable.Empty(); + } + else + { + printerFiles = calibrationPrintFileNames; + } */ - string[] calibrationPrintFileNames = printerCalibrationFiles.Split(';'); - if (calibrationPrintFileNames.Length < 0) - { - printerFiles = Enumerable.Empty(); - } - else - { - printerFiles = calibrationPrintFileNames; - } */ - - var oemParts = AggContext.StaticData.GetFiles(Path.Combine("OEMSettings", "SampleParts")); - Items = oemParts.Select(s => - { - // TODO: Won't work on Android - make stream based - return new FileSystemFileItem(AggContext.StaticData.MapPath(s)); - }).ToList(); - - UiThread.RunOnIdle(this.OnReloaded); - }); + var oemParts = AggContext.StaticData.GetFiles(Path.Combine("OEMSettings", "SampleParts")); + Items = oemParts.Select(s => + { + // TODO: Won't work on Android - make stream based + return new FileSystemFileItem(AggContext.StaticData.MapPath(s)); + }).ToList(); } public override void Dispose() diff --git a/Library/Providers/CreatorsContainer.cs b/Library/Providers/MatterControl/PrintHistoryContainer.cs similarity index 72% rename from Library/Providers/CreatorsContainer.cs rename to Library/Providers/MatterControl/PrintHistoryContainer.cs index 9ee4236d0..50637713b 100644 --- a/Library/Providers/CreatorsContainer.cs +++ b/Library/Providers/MatterControl/PrintHistoryContainer.cs @@ -27,17 +27,27 @@ of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. */ +using System.Collections.Generic; +using System.Linq; +using MatterHackers.Localizations; +using MatterHackers.MatterControl.PrintHistory; namespace MatterHackers.MatterControl.Library { - public class CreatorsContainer : LibraryContainer + public class PrintHistoryContainer : LibraryContainer { - public CreatorsContainer() + public PrintHistoryContainer() { + this.ChildContainers = new List(); + this.Items = new List(); + this.Name = "Print History".Localize(); + this.DefaultView = typeof(HistoryListView); } - public override void Dispose() + public override void Load() { + // PrintItems projected onto FileSystemFileItem + Items = PrintHistoryData.Instance.GetHistoryItems(25).Select(f => new PrintHistoryItem(f)).ToList(); } } } diff --git a/Library/Providers/MatterControl/HistoryContainer.cs b/Library/Providers/MatterControl/PrintHistoryItem.cs similarity index 68% rename from Library/Providers/MatterControl/HistoryContainer.cs rename to Library/Providers/MatterControl/PrintHistoryItem.cs index 8e24bf9f7..933e09382 100644 --- a/Library/Providers/MatterControl/HistoryContainer.cs +++ b/Library/Providers/MatterControl/PrintHistoryItem.cs @@ -28,19 +28,14 @@ either expressed or implied, of the FreeBSD Project. */ using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; -using MatterHackers.Agg.UI; -using MatterHackers.Localizations; using MatterHackers.MatterControl.DataStorage; -using MatterHackers.MatterControl.PrintHistory; namespace MatterHackers.MatterControl.Library { - public class HistoryRowItem : ILibraryContentStream + public class PrintHistoryItem : ILibraryContentStream { - public HistoryRowItem(PrintTask printTask) + public PrintHistoryItem(PrintTask printTask) { this.PrintTask = printTask; } @@ -64,38 +59,10 @@ namespace MatterHackers.MatterControl.Library public bool IsVisible => true; public bool LocalContentExists => true; - + public Task GetContentStream(Action reportProgress) { throw new NotImplementedException(); } } - - public class HistoryContainer : LibraryContainer - { - public HistoryContainer() - { - this.ChildContainers = new List(); - this.Items = new List(); - this.Name = "Print History".Localize(); - this.DefaultView = typeof(HistoryListView); - - //PrintHistoryData.Instance.ItemAdded.RegisterEvent((sender, e) => OnDataReloaded(null), ref unregisterEvent); - - this.ReloadContainer(); - } - - private void ReloadContainer() - { - Task.Run(() => - { - var printHistory = PrintHistoryData.Instance.GetHistoryItems(25); - - // PrintItems projected onto FileSystemFileItem - Items = printHistory.Select(f => new HistoryRowItem(f)).ToList(); - - UiThread.RunOnIdle(this.OnReloaded); - }); - } - } } diff --git a/Library/Providers/MatterControl/PrintQueueContainer.cs b/Library/Providers/MatterControl/PrintQueueContainer.cs index 47a453c5e..6add74be2 100644 --- a/Library/Providers/MatterControl/PrintQueueContainer.cs +++ b/Library/Providers/MatterControl/PrintQueueContainer.cs @@ -46,28 +46,20 @@ namespace MatterHackers.MatterControl.Library this.ChildContainers = new List(); this.Items = new List(); this.Name = "Print Queue".Localize(); - - Task.Run(() => - { - this.ReloadContainer(); - }); } - private void ReloadContainer() + public override void Load() { this.Items = QueueData.Instance.PrintItems.Select(p => new FileSystemFileItem(p.FileLocation) { Name = p.Name }).ToList(); - - UiThread.RunOnIdle(this.OnReloaded); } public override async void Add(IEnumerable items) { await AddAllItems(items); - - this.ReloadContainer(); + this.OnContentChanged(); } public static async Task AddAllItems(IEnumerable items) @@ -131,7 +123,7 @@ namespace MatterHackers.MatterControl.Library } } - this.ReloadContainer(); + this.OnContentChanged(); } public override bool AllowAction(ContainerActions containerActions) diff --git a/Library/Providers/MatterControl/SqliteLibraryContainer.cs b/Library/Providers/MatterControl/SqliteLibraryContainer.cs index d74813f88..0e492bb12 100644 --- a/Library/Providers/MatterControl/SqliteLibraryContainer.cs +++ b/Library/Providers/MatterControl/SqliteLibraryContainer.cs @@ -37,14 +37,10 @@ using MatterHackers.Agg.UI; using MatterHackers.DataConverters3D; using MatterHackers.Localizations; using MatterHackers.MatterControl.DataStorage; -using MatterHackers.MatterControl.PrinterCommunication; using MatterHackers.MatterControl.PrintQueue; using MatterHackers.PolygonMesh; using MatterHackers.PolygonMesh.Processors; - - - namespace MatterHackers.MatterControl.Library { public class SqliteFileItem : FileSystemFileItem @@ -63,17 +59,24 @@ namespace MatterHackers.MatterControl.Library { protected List childCollections = new List(); + public SqliteLibraryContainer() + { + var rootCollection = Datastore.Instance.dbSQLite.Table().Where(v => v.Name == "_library").Take(1).FirstOrDefault(); + + this.Initialize(rootCollection?.Id ?? 0); + } + public SqliteLibraryContainer(int collectionID) + { + this.Initialize(collectionID); + } + + private void Initialize(int collectionID) { this.ChildContainers = new List(); this.Items = new List(); this.Name = "Local Library".Localize(); this.CollectionID = collectionID; - - //PrintHistoryData.Instance.ItemAdded.RegisterEvent((sender, e) => OnDataReloaded(null), ref unregisterEvent); - // ItemAdded.RegisterEvent(DatabaseFileChange, ref unregisterEvents); - - this.ReloadContainer(); } public int CollectionID { get; private set; } @@ -89,44 +92,38 @@ namespace MatterHackers.MatterControl.Library if (base.KeywordFilter != value) { base.KeywordFilter = value; - this.ReloadContainer(); + this.OnContentChanged(); } } } - private void ReloadContainer() + public override void Load() { - Task.Run(() => + childCollections = GetChildCollections(); + + this.ChildContainers = childCollections.Select(c => new SqliteLibraryContainerLink() { - childCollections = GetChildCollections(); + ContainerID = c.Id, Name = c.Name }).ToList(); // - this.ChildContainers = childCollections.Select(c => new SqliteLibraryContainerLink() + // PrintItems projected onto FileSystemFileItem + Items = GetLibraryItems(KeywordFilter).Select(printItem => + { + if (File.Exists(printItem.FileLocation)) { - ContainerID = c.Id, Name = c.Name }).ToList(); // - - // PrintItems projected onto FileSystemFileItem - Items = GetLibraryItems(KeywordFilter).Select(printItem => + return new SqliteFileItem(printItem); + } + else { - if (File.Exists(printItem.FileLocation)) - { - return new SqliteFileItem(printItem); - } - else - { - return new MessageItem($"{printItem.Name} (Missing)"); - //return new MissingFileItem() // Needs to return a content specific icon with a missing overlay - needs to lack all print operations - } - }).ToList(); - - UiThread.RunOnIdle(this.OnReloaded); - }); + return new MessageItem($"{printItem.Name} (Missing)"); + //return new MissingFileItem() // Needs to return a content specific icon with a missing overlay - needs to lack all print operations + } + }).ToList(); } public override async void Add(IEnumerable items) { await Task.Run(async () => { - foreach (var item in items) { switch (item) @@ -203,8 +200,7 @@ namespace MatterHackers.MatterControl.Library } } - this.ReloadContainer(); - this.OnReloaded(); + this.OnContentChanged(); }); } @@ -237,7 +233,7 @@ namespace MatterHackers.MatterControl.Library this.Items.Remove(item); } - this.OnReloaded(); + this.OnContentChanged(); } public override void Rename(ILibraryItem selectedItem, string revisedName) @@ -259,7 +255,7 @@ namespace MatterHackers.MatterControl.Library } } - this.ReloadContainer(); + this.OnContentChanged(); } /// @@ -354,7 +350,7 @@ namespace MatterHackers.MatterControl.Library public bool IsProtected { get; set; } = false; public bool IsReadOnly { get; set; } = false; - + public bool IsVisible { get; set; } = true; public Task GetContainer(Action reportProgress) diff --git a/Library/Providers/RootLibraryContainer.cs b/Library/Providers/RootLibraryContainer.cs index a617907b3..f09570405 100644 --- a/Library/Providers/RootLibraryContainer.cs +++ b/Library/Providers/RootLibraryContainer.cs @@ -29,16 +29,14 @@ either expressed or implied, of the FreeBSD Project. using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using MatterHackers.Agg.Image; -using MatterHackers.Agg.UI; namespace MatterHackers.MatterControl.Library { - public partial class RootLibraryContainer : ILibraryContainer + public class RootLibraryContainer : ILibraryContainer { - public event EventHandler Reloaded; + public event EventHandler ContentChanged; public RootLibraryContainer(List items) { @@ -69,6 +67,8 @@ namespace MatterHackers.MatterControl.Library return Task.FromResult(null); } + public void Load() { } + public void Dispose() { } diff --git a/Library/Providers/SDCard/SDCardContainer.cs b/Library/Providers/SDCard/SDCardContainer.cs index 9060eaf6c..b5713932a 100644 --- a/Library/Providers/SDCard/SDCardContainer.cs +++ b/Library/Providers/SDCard/SDCardContainer.cs @@ -29,9 +29,11 @@ either expressed or implied, of the FreeBSD Project. using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using MatterHackers.Agg; using MatterHackers.Agg.Image; +using MatterHackers.Agg.UI; using MatterHackers.Localizations; namespace MatterHackers.MatterControl.Library @@ -42,26 +44,33 @@ namespace MatterHackers.MatterControl.Library private EventHandler unregisterEvents; + private PrinterConfig printer; + + private AutoResetEvent autoResetEvent; + public SDCardContainer() { this.ChildContainers = new List(); this.Items = new List(); this.Name = "SD Card".Localize(); - LoadFilesFromSD(); + + printer = ApplicationController.Instance.ActivePrinter; } - public void LoadFilesFromSD() + public override void Load() { - var printer = ApplicationController.Instance.ActivePrinter; - if (printer.Connection.PrinterIsConnected && !(printer.Connection.PrinterIsPrinting || printer.Connection.PrinterIsPaused)) { + autoResetEvent = new AutoResetEvent(false); printer.Connection.ReadLine.RegisterEvent(Printer_LineRead, ref unregisterEvents); gotBeginFileList = false; printer.Connection.SendLineToPrinterNow("M21\r\nM20"); + + // Ask for files and wait for response + autoResetEvent.WaitOne(); } } @@ -76,8 +85,7 @@ namespace MatterHackers.MatterControl.Library private void Printer_LineRead(object sender, EventArgs e) { - var currentEvent = e as StringEventArgs; - if (currentEvent != null) + if (e is StringEventArgs currentEvent) { if (!currentEvent.Data.StartsWith("echo:")) { @@ -88,6 +96,13 @@ namespace MatterHackers.MatterControl.Library this.Items.Clear(); break; + case "End file list": + printer.Connection.ReadLine.UnregisterEvent(Printer_LineRead, ref unregisterEvents); + + // Release the Load WaitOne + autoResetEvent.Set(); + break; + default: if (gotBeginFileList) { @@ -103,11 +118,6 @@ namespace MatterHackers.MatterControl.Library } } break; - - case "End file list": - ApplicationController.Instance.ActivePrinter.Connection.ReadLine.UnregisterEvent(Printer_LineRead, ref unregisterEvents); - this.OnReloaded(); - break; } } } @@ -116,7 +126,10 @@ namespace MatterHackers.MatterControl.Library public override void Dispose() { // In case "End file list" is never received - ApplicationController.Instance.ActivePrinter.Connection.ReadLine.UnregisterEvent(Printer_LineRead, ref unregisterEvents); + printer.Connection.ReadLine.UnregisterEvent(Printer_LineRead, ref unregisterEvents); + + // Release the Load WaitOne + autoResetEvent?.Set(); } } } diff --git a/Library/Providers/Zip/LocalZipContainerLink.cs b/Library/Providers/Zip/LocalZipContainerLink.cs index efa9babe6..e2ee5e652 100644 --- a/Library/Providers/Zip/LocalZipContainerLink.cs +++ b/Library/Providers/Zip/LocalZipContainerLink.cs @@ -66,10 +66,15 @@ namespace MatterHackers.MatterControl.Library this.Name = currentDirectory.Split('/').Last(); } } - + public Task GetContainer(Action reportProgress) { - return Task.FromResult(new ZipMemoryContainer(this.currentDirectory, this.Path)); + return Task.FromResult( + new ZipMemoryContainer() + { + RelativeDirectory = this.currentDirectory, + Path = this.Path + }); } } } diff --git a/Library/Providers/Zip/ZipMemoryContainer.cs b/Library/Providers/Zip/ZipMemoryContainer.cs index 8413e0d6d..667b66377 100644 --- a/Library/Providers/Zip/ZipMemoryContainer.cs +++ b/Library/Providers/Zip/ZipMemoryContainer.cs @@ -32,25 +32,35 @@ using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; +using System.Threading.Tasks; +using MatterHackers.Agg.UI; namespace MatterHackers.MatterControl.Library { public class ZipMemoryContainer : LibraryContainer { - public ZipMemoryContainer(string relativeDirectory, string path) + public ZipMemoryContainer() + { + } + + public string RelativeDirectory { get; set; } + + public string Path { get; set; } + + public override void Load() { //string hashCode = this.Url.GetHashCode().ToString(); var items = new Dictionary(); var directories = new HashSet(); - using (var file = File.OpenRead(path)) + using (var file = File.OpenRead(this.Path)) using (var zip = new ZipArchive(file, ZipArchiveMode.Read)) { foreach (var entry in zip.Entries) { - if (entry.FullName.StartsWith(relativeDirectory)) + if (entry.FullName.StartsWith(RelativeDirectory)) { - string remainingPath = entry.FullName.Substring(relativeDirectory.Length)?.Trim().TrimStart('/'); + string remainingPath = entry.FullName.Substring(RelativeDirectory.Length)?.Trim().TrimStart('/'); var segments = remainingPath.Split('/'); var firstDirectory = segments.First(); @@ -68,15 +78,15 @@ namespace MatterHackers.MatterControl.Library } } - this.Name = System.IO.Path.GetFileNameWithoutExtension(path); + this.Name = System.IO.Path.GetFileNameWithoutExtension(this.Path); - this.ChildContainers = directories.Where(d => !string.IsNullOrEmpty(d)).Select(d => - new LocalZipContainerLink(path) + this.ChildContainers = directories.Where(d => !string.IsNullOrEmpty(d)).Select(d => + new LocalZipContainerLink(this.Path) { - CurrentDirectory = relativeDirectory.Length == 0 ? d : $"{relativeDirectory}/{d}" + CurrentDirectory = RelativeDirectory.Length == 0 ? d : $"{RelativeDirectory}/{d}" }).ToList(); - this.Items = items.Select(kvp => new ZipMemoryItem(path, relativeDirectory.Length == 0 ? kvp.Key : $"{relativeDirectory}/{kvp.Key}", kvp.Value)).ToList(); + this.Items = items.Select(kvp => new ZipMemoryItem(this.Path, RelativeDirectory.Length == 0 ? kvp.Key : $"{RelativeDirectory}/{kvp.Key}", kvp.Value)).ToList(); } public override void Dispose() diff --git a/Library/Providers/Zip/ZipMemoryItem.cs b/Library/Providers/Zip/ZipMemoryItem.cs index 29e18b79b..c5051854f 100644 --- a/Library/Providers/Zip/ZipMemoryItem.cs +++ b/Library/Providers/Zip/ZipMemoryItem.cs @@ -50,7 +50,7 @@ namespace MatterHackers.MatterControl.Library public string RelativePath { get; set; } public string ContentType => System.IO.Path.GetExtension(this.Name).ToLower().Trim('.'); - + public string AssetPath { get; } = null; public string FileName => System.IO.Path.GetFileName(this.Name); diff --git a/Library/Widgets/ListView/IconListView.cs b/Library/Widgets/ListView/IconListView.cs index 8066cbf86..130c9aee9 100644 --- a/Library/Widgets/ListView/IconListView.cs +++ b/Library/Widgets/ListView/IconListView.cs @@ -150,6 +150,8 @@ namespace MatterHackers.MatterControl.CustomWidgets cellIndex = 0; rowButtonContainer = null; allIconViews.Clear(); + + this.CloseAllChildren(); } } diff --git a/Library/Widgets/ListView/ListView.cs b/Library/Widgets/ListView/ListView.cs index 8e44e01c6..e450a3f45 100644 --- a/Library/Widgets/ListView/ListView.cs +++ b/Library/Widgets/ListView/ListView.cs @@ -32,6 +32,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; +using System.Threading.Tasks; using MatterHackers.Agg; using MatterHackers.Agg.Image; using MatterHackers.Agg.Platform; @@ -46,10 +47,13 @@ namespace MatterHackers.MatterControl.CustomWidgets { private EventHandler unregisterEvents; - internal GuiWidget contentView; - private ILibraryContext LibraryContext; + /// + /// The original content view before it was replaced by a container default view + /// + private GuiWidget stashedContentView = new IconListView(); + // Default constructor uses IconListView public ListView(ILibraryContext context) : this(context, new IconListView()) @@ -69,7 +73,7 @@ namespace MatterHackers.MatterControl.CustomWidgets this.ListContentView = libraryView; context.ContainerChanged += ActiveContainer_Changed; - context.ContainerReloaded += ActiveContainer_Reloaded; + context.ContentChanged += ActiveContainer_ContentChanged; } public bool ShowItems { get; set; } = true; @@ -83,43 +87,46 @@ namespace MatterHackers.MatterControl.CustomWidgets public RGBA_Bytes ThumbnailBackground { get; } = ActiveTheme.Instance.TertiaryBackgroundColor.AdjustLightness(1.05).GetAsRGBA_Bytes(); public RGBA_Bytes ThumbnailForeground { get; set; } = ActiveTheme.Instance.PrimaryAccentColor; - private GuiWidget stashedView = null; - - private void ActiveContainer_Changed(object sender, ContainerChangedEventArgs e) + private async void ActiveContainer_Changed(object sender, ContainerChangedEventArgs e) { var activeContainer = e.ActiveContainer; + // Anytime the container changes, Type targetType = activeContainer?.DefaultView; - if (targetType != null + if (targetType != null && targetType != this.ListContentView.GetType()) { - stashedView = this.contentView; + // If no original view is stored in stashedContentView then store a reference before the switch + if (stashedContentView == null) + { + stashedContentView = this.ListContentView; + } // If the current view doesn't match the view requested by the container, construct and switch to the requested view var targetView = Activator.CreateInstance(targetType) as GuiWidget; if (targetView != null) { - this.SetContentView(targetView); + this.ListContentView = targetView; } } - else if (stashedView != null) + else if (stashedContentView != null) { // Switch back to the original view - this.SetContentView(stashedView); - stashedView = null; + this.ListContentView = stashedContentView; + stashedContentView = null; } - DisplayContainerContent(activeContainer); + await DisplayContainerContent(activeContainer); } - public void Reload() + public async Task Reload() { - DisplayContainerContent(ActiveContainer); + await DisplayContainerContent(ActiveContainer); } - private void ActiveContainer_Reloaded(object sender, EventArgs e) + private async void ActiveContainer_ContentChanged(object sender, EventArgs e) { - DisplayContainerContent(ActiveContainer); + await DisplayContainerContent(ActiveContainer); } private List items = new List(); @@ -130,14 +137,13 @@ namespace MatterHackers.MatterControl.CustomWidgets /// Empties the list children and repopulates the list with the source container content /// /// The container to load - private void DisplayContainerContent(ILibraryContainer sourceContainer) + private async Task DisplayContainerContent(ILibraryContainer sourceContainer) { if (this.ActiveContainer is ILibraryWritableContainer activeWritable) { activeWritable.ItemContentChanged -= WritableContainer_ItemContentChanged; } - UiThread.RunOnIdle(() => { if (sourceContainer == null) { @@ -154,6 +160,12 @@ namespace MatterHackers.MatterControl.CustomWidgets var itemsContentView = contentView as IListContentView; itemsContentView.ClearItems(); + // Wait for the container to load + await Task.Run(() => + { + sourceContainer.Load(); + }); + int width = itemsContentView.ThumbWidth; int height = itemsContentView.ThumbHeight; @@ -197,7 +209,7 @@ namespace MatterHackers.MatterControl.CustomWidgets } this.Invalidate(); - }); + } } private void WritableContainer_ItemContentChanged(object sender, ItemChangedEventArgs e) @@ -216,16 +228,12 @@ namespace MatterHackers.MatterControl.CustomWidgets List } - private void SetContentView(GuiWidget contentView) - { - this.ScrollArea.CloseAllChildren(); - - this.contentView = contentView; - this.contentView.HAnchor = HAnchor.Stretch; - this.contentView.Name = "Library ListView"; - this.AddChild(this.contentView); - } + // Default to IconListView + private GuiWidget contentView = new IconListView(); + /// + /// The GuiWidget responsible for rendering ListViewItems + /// public GuiWidget ListContentView { get { return contentView; } @@ -233,13 +241,15 @@ namespace MatterHackers.MatterControl.CustomWidgets { if (value is IListContentView) { - SetContentView(value); - - // Allow some time for layout to occur and contentView to become sized before loading content - UiThread.RunOnIdle(() => + if (contentView != null) { - DisplayContainerContent(ActiveContainer); - }); + this.ScrollArea.CloseAllChildren(); + + this.contentView = value; + this.contentView.HAnchor = HAnchor.Stretch; + this.contentView.Name = "Library ListView"; + this.AddChild(this.contentView); + } } else { @@ -364,12 +374,22 @@ namespace MatterHackers.MatterControl.CustomWidgets public ListViewItem DragSourceRowItem { get; set; } + public override void OnLoad(EventArgs args) + { + if (this.ListContentView.Children.Count <= 0) + { + this.Reload(); + } + + base.OnLoad(args); + } + public override void OnClosed(ClosedEventArgs e) { if (this.LibraryContext != null) { this.LibraryContext.ContainerChanged -= this.ActiveContainer_Changed; - this.LibraryContext.ContainerReloaded -= this.ActiveContainer_Reloaded; + this.LibraryContext.ContentChanged -= this.ActiveContainer_ContentChanged; } unregisterEvents?.Invoke(this, null); @@ -377,4 +397,3 @@ namespace MatterHackers.MatterControl.CustomWidgets } } } - \ No newline at end of file diff --git a/Library/Widgets/PrintLibraryWidget.cs b/Library/Widgets/PrintLibraryWidget.cs index cc8aad374..36d424851 100644 --- a/Library/Widgets/PrintLibraryWidget.cs +++ b/Library/Widgets/PrintLibraryWidget.cs @@ -100,7 +100,7 @@ namespace MatterHackers.MatterControl.PrintLibrary Name = "Show Folders Toggle", Checked = UserSettings.Instance.get("ShowContainers") == "1" }; - showFolders.CheckedStateChanged += (s, e) => + showFolders.CheckedStateChanged += async (s, e) => { UserSettings.Instance.set("ShowContainers", showFolders.Checked ? "1" : "0"); libraryView.Reload(); @@ -236,12 +236,11 @@ namespace MatterHackers.MatterControl.PrintLibrary // Release if (e.PreviousContainer != null) { - e.PreviousContainer.Reloaded -= UpdateStatus; + e.PreviousContainer.ContentChanged -= UpdateStatus; } var activeContainer = this.libraryView.ActiveContainer; - var writableContainer = activeContainer as ILibraryWritableContainer; bool containerSupportsEdits = activeContainer is ILibraryWritableContainer; @@ -252,7 +251,7 @@ namespace MatterHackers.MatterControl.PrintLibrary searchInput.Text = activeContainer.KeywordFilter; breadCrumbWidget.SetBreadCrumbs(activeContainer); - activeContainer.Reloaded += UpdateStatus; + activeContainer.ContentChanged += UpdateStatus; UpdateStatus(null, null); } @@ -639,7 +638,7 @@ namespace MatterHackers.MatterControl.PrintLibrary { if (libraryView?.ActiveContainer != null) { - libraryView.ActiveContainer.Reloaded -= UpdateStatus; + libraryView.ActiveContainer.ContentChanged -= UpdateStatus; ApplicationController.Instance.Library.ContainerChanged -= Library_ContainerChanged; } @@ -745,27 +744,6 @@ namespace MatterHackers.MatterControl.PrintLibrary WizardWindow.Show(exportPage); } - /* - public async Task GetPrintItemWrapperAsync() - { - return await libraryProvider.GetPrintItemWrapperAsync(this.ItemIndex); - } */ - - // TODO: We've discussed not doing popup edit in a new window. That's what this did, not worth porting yet... - /* - private void editButton_Click(object sender, EventArgs e) - { - //Open export options - if (libraryDataView.SelectedItems.Count == 1) - { - - OpenPartViewWindow(PartPreviewWindow.View3DWidget.OpenMode.Editing); - - LibraryRowItem libraryItem = libraryDataView.SelectedItems[0]; - libraryItem.Edit(); - } - } */ - public override void OnMouseEnterBounds(MouseEventArgs mouseEvent) { if (mouseEvent.DragFiles?.Count > 0) diff --git a/MatterControl.csproj b/MatterControl.csproj index eca11cc9a..f89fa1596 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -150,6 +150,8 @@ + + @@ -197,7 +199,6 @@ - @@ -206,7 +207,6 @@ - diff --git a/MatterControlApplication.cs b/MatterControlApplication.cs index 4afc00372..103b321e6 100644 --- a/MatterControlApplication.cs +++ b/MatterControlApplication.cs @@ -378,38 +378,6 @@ namespace MatterHackers.MatterControl return instance; } - public static void WriteTestGCodeFile() - { - using (StreamWriter file = new StreamWriter("PerformanceTest.gcode")) - { - //int loops = 150000; - int loops = 150; - int steps = 200; - double radius = 50; - Vector2 center = new Vector2(150, 100); - - file.WriteLine("G28 ; home all axes"); - file.WriteLine("G90 ; use absolute coordinates"); - file.WriteLine("G21 ; set units to millimeters"); - file.WriteLine("G92 E0"); - file.WriteLine("G1 F7800"); - file.WriteLine("G1 Z" + (5).ToString()); - WriteMove(file, center); - - for (int loop = 0; loop < loops; loop++) - { - for (int step = 0; step < steps; step++) - { - Vector2 nextPosition = new Vector2(radius, 0); - nextPosition.Rotate(MathHelper.Tau / steps * step); - WriteMove(file, center + nextPosition); - } - } - - file.WriteLine("M84 ; disable motors"); - } - } - public void LaunchBrowser(string targetUri) { UiThread.RunOnIdle(() => @@ -465,23 +433,23 @@ namespace MatterHackers.MatterControl QueueData.Instance.SaveDefaultQueue(); // If we are waiting for a response and get another request, just cancel the close until we get a response. - if(closeMessageBoxIsOpen) + if(exitDialogOpen) { cancelClose = true; } - if (!closeHasBeenConfirmed - && !closeMessageBoxIsOpen + if (!ApplicationExiting + && !exitDialogOpen && ApplicationController.Instance.ActivePrinter.Connection.PrinterIsPrinting) { cancelClose = true; // Record that we are waiting for a response to the request to close - closeMessageBoxIsOpen = true; + exitDialogOpen = true; if (ApplicationController.Instance.ActivePrinter.Connection.CommunicationState != CommunicationStates.PrintingFromSd) { // Needed as we can't assign to CancelClose inside of the lambda below - StyledMessageBox.ShowMessageBox(ConditionalyCloseNow, + StyledMessageBox.ShowMessageBox(ConditionalExit, "Are you sure you want to abort the current print and close MatterControl?".Localize(), "Abort Print".Localize(), StyledMessageBox.MessageType.YES_NO); @@ -489,7 +457,7 @@ namespace MatterHackers.MatterControl else { StyledMessageBox.ShowMessageBox( - ConditionalyCloseNow, + ConditionalExit, "Are you sure you want exit while a print is running from SD Card?\n\nNote: If you exit, it is recommended you wait until the print is completed before running MatterControl again.".Localize(), "Exit while printing".Localize(), StyledMessageBox.MessageType.YES_NO); @@ -497,7 +465,17 @@ namespace MatterHackers.MatterControl } else if (PartsSheet.IsSaving()) { - StyledMessageBox.ShowMessageBox(onConfirmExit, savePartsSheetExitAnywayMessage, confirmExit, StyledMessageBox.MessageType.YES_NO); + StyledMessageBox.ShowMessageBox( + (exitAnyway) => + { + if (exitAnyway) + { + base.OnClosing(out _); + } + }, + savePartsSheetExitAnywayMessage, + confirmExit, + StyledMessageBox.MessageType.YES_NO); cancelClose = true; } else if(!cancelClose) // only check if we have not already canceled @@ -506,26 +484,37 @@ namespace MatterHackers.MatterControl } } - bool closeHasBeenConfirmed = false; - bool closeMessageBoxIsOpen = false; - private void ConditionalyCloseNow(bool continueWithShutdown) + public bool ApplicationExiting { get; private set; } = false; + + private bool exitDialogOpen = false; + + private void ConditionalExit(bool exitConfirmed) { - // Response received, cecord that we are not waiting anymore. - closeMessageBoxIsOpen = false; - if (continueWithShutdown) + // Record that the exitDialog has closed + exitDialogOpen = false; + + // Continue with shutdown if exit confirmed by user + if (exitConfirmed) { - closeHasBeenConfirmed = true; - bool printingFromSdCard = ApplicationController.Instance.ActivePrinter.Connection.CommunicationState == CommunicationStates.PrintingFromSd - || (ApplicationController.Instance.ActivePrinter.Connection.CommunicationState == CommunicationStates.Paused - && ApplicationController.Instance.ActivePrinter.Connection.PrePauseCommunicationState == CommunicationStates.PrintingFromSd); - if (!printingFromSdCard) + this.ApplicationExiting = true; + + ApplicationController.Instance.Shutdown(); + + // Always call PrinterConnection.Disable on exit unless PrintingFromSd + PrinterConnection printerConnection = ApplicationController.Instance.ActivePrinter.Connection; + switch(printerConnection.CommunicationState) { - ApplicationController.Instance.ActivePrinter.Connection.Disable(); + case CommunicationStates.PrintingFromSd: + case CommunicationStates.Paused when printerConnection.PrePauseCommunicationState == CommunicationStates.PrintingFromSd: + break; + + default: + printerConnection.Disable(); + break; } - MatterControlApplication app = MatterControlApplication.Instance; - app.RestartOnClose = false; - app.Close(); + this.RestartOnClose = false; + this.Close(); } } @@ -590,44 +579,6 @@ namespace MatterHackers.MatterControl base.OnLoad(args); } - private static void HtmlWindowTest() - { - try - { - SystemWindow htmlTestWindow = new SystemWindow(640, 480); - string htmlContent = ""; - if (true) - { - string releaseNotesFile = Path.Combine("C:\\Users\\lbrubaker\\Downloads", "test1.html"); - htmlContent = File.ReadAllText(releaseNotesFile); - } - else - { - WebClient webClient = new WebClient(); - htmlContent = webClient.DownloadString("http://www.matterhackers.com/s/store?q=pla"); - } - - HtmlWidget content = new HtmlWidget(htmlContent, RGBA_Bytes.Black); - content.AddChild(new GuiWidget() - { - HAnchor = HAnchor.Absolute, - VAnchor = VAnchor.Stretch - }); - content.VAnchor |= VAnchor.Top; - content.BackgroundColor = RGBA_Bytes.White; - htmlTestWindow.AddChild(content); - htmlTestWindow.BackgroundColor = RGBA_Bytes.Cyan; - UiThread.RunOnIdle((state) => - { - htmlTestWindow.ShowAsSystemWindow(); - }, 1); - } - catch - { - int stop = 1; - } - } - public override void OnMouseMove(MouseEventArgs mouseEvent) { // run this first to make sure a child has the chance to take the drag drop event @@ -683,11 +634,6 @@ namespace MatterHackers.MatterControl } } - private static void WriteMove(StreamWriter file, Vector2 center) - { - file.WriteLine("G1 X" + center.x.ToString() + " Y" + center.y.ToString()); - } - private void CheckOnPrinter() { try @@ -743,15 +689,6 @@ namespace MatterHackers.MatterControl } } - private void onConfirmExit(bool messageBoxResponse) - { - bool CancelClose; - if (messageBoxResponse) - { - base.OnClosing(out CancelClose); - } - } - private static void AssertDebugNotDefined() { #if DEBUG @@ -780,4 +717,3 @@ namespace MatterHackers.MatterControl } } } - diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index 3b4472353..6372949c5 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit 3b447235354fa0fb63daba924b3ec42209d7bd2f +Subproject commit 6372949c59f4b355ac3744f5b0938d42d0451183 diff --git a/Tests/MatterControl.AutomationTests/LibraryContainerTests.cs b/Tests/MatterControl.AutomationTests/LibraryContainerTests.cs new file mode 100644 index 000000000..68d62f3c6 --- /dev/null +++ b/Tests/MatterControl.AutomationTests/LibraryContainerTests.cs @@ -0,0 +1,263 @@ +/* +Copyright (c) 2017, John Lewin +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using MatterHackers.Agg; +using MatterHackers.Agg.Platform; +using MatterHackers.Agg.UI; +using MatterHackers.MatterControl.DataStorage; +using MatterHackers.MatterControl.Library; +using MatterHackers.MatterControl.Tests.Automation; +using NUnit.Framework; + +namespace MatterControl.Tests.MatterControl +{ + [TestFixture, Category("LibraryContainerTests"), RunInApplicationDomain, Apartment(ApartmentState.STA)] + public class LibraryContainerTests + { + [Test] + public Task TestExistsForEachContainerType() + { + AggContext.StaticData = new FileSystemStaticData(TestContext.CurrentContext.ResolveProjectPath(4, "StaticData")); + MatterControlUtilities.OverrideAppDataLocation(TestContext.CurrentContext.ResolveProjectPath(4)); + + // Find all test methods on this test class + var thisClassMethods = this.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance); + + // Find and validate all ILibraryContainer types, skipping abstract classes + foreach (var containerType in PluginFinder.FindTypes().Where(fieldType => !fieldType.IsAbstract)) + { + string expectedTestName = $"{containerType.Name}Test"; + Assert.AreEqual( + 1, + thisClassMethods.Where(m => m.Name == expectedTestName).Count(), + "Test for LibraryContainer missing, not yet created or typo'd - Expected: " + expectedTestName); + } + + return Task.CompletedTask; + } + + [Test] + public async Task NoContentChangedOnLoad() + { + AggContext.StaticData = new FileSystemStaticData(TestContext.CurrentContext.ResolveProjectPath(4, "StaticData")); + MatterControlUtilities.OverrideAppDataLocation(TestContext.CurrentContext.ResolveProjectPath(4)); + + bool onIdlePumpActive = true; + + var uiPump = Task.Run(() => + { + while (onIdlePumpActive) + { + UiThread.InvokePendingActions(); + Thread.Sleep(10); + }; + + Console.Write("Exiting"); + }); + + // Find and validate all ILibraryContainer types, skipping abstract classes + foreach (var containerType in PluginFinder.FindTypes().Where(fieldType => !fieldType.IsAbstract)) + { + var args = new List(); + + if (containerType == typeof(FileSystemContainer)) + { + args.Add(TestContext.CurrentContext.ResolveProjectPath(4)); + } + else if (containerType == typeof(RootLibraryContainer)) + { + // TODO: Not sure how to test RootLibrary given content loads after MatterControl init is finished, skipping for now + continue; + } + + if (Activator.CreateInstance(containerType, args.ToArray()) is ILibraryContainer libraryContainer) + { + if (libraryContainer is ZipMemoryContainer zipContainer) + { + zipContainer.Path = TestContext.CurrentContext.ResolveProjectPath(4, "Tests", "TestData", "TestParts", "Batman.zip"); + zipContainer.RelativeDirectory = Path.GetDirectoryName(zipContainer.Path); + } + + int changedCount = 0; + libraryContainer.ContentChanged += (s, e) => + { + changedCount++; + }; + + await Task.Run(() => + { + libraryContainer.Load(); + }); + + // Allow time for invalid additional reloads + await Task.Delay(300); + + // Verify Reload is called; + Assert.AreEqual(0, changedCount, "Expected reload count not hit - container should fire reload event after acquiring content"); + } + } + + onIdlePumpActive = false; + } + + [Test] + public async Task AddFiresContentChangedEvent() + { + AggContext.StaticData = new FileSystemStaticData(TestContext.CurrentContext.ResolveProjectPath(4, "StaticData")); + MatterControlUtilities.OverrideAppDataLocation(TestContext.CurrentContext.ResolveProjectPath(4)); + + string filePath = TestContext.CurrentContext.ResolveProjectPath(4, "Tests", "TestData", "TestParts", "Batman.stl"); + + bool onIdlePumpActive = true; + + var uiPump = Task.Run(() => + { + while (onIdlePumpActive) + { + UiThread.InvokePendingActions(); + Thread.Sleep(10); + }; + + Console.Write("Exiting"); + }); + + Type writable = typeof(ILibraryWritableContainer); + + // Find and validate all ILibraryContainer types, skipping abstract classes + foreach (var containerType in PluginFinder.FindTypes().Where(fieldType => !fieldType.IsAbstract)) + { + var args = new List(); + + if (containerType == typeof(FileSystemContainer)) + { + Directory.CreateDirectory(ApplicationDataStorage.Instance.ApplicationTempDataPath); + args.Add(ApplicationDataStorage.Instance.ApplicationTempDataPath); + } + else if (containerType == typeof(RootLibraryContainer) + || !writable.IsAssignableFrom(containerType)) + { + // TODO: Not sure how to test RootLibrary given content loads after MatterControl init is finished, skipping for now + continue; + } + + if (Activator.CreateInstance(containerType, args.ToArray()) is ILibraryWritableContainer libraryContainer) + { + if (libraryContainer is ZipMemoryContainer zipContainer) + { + zipContainer.Path = TestContext.CurrentContext.ResolveProjectPath(4, "Tests", "TestData", "TestParts", "Batman.zip"); + zipContainer.RelativeDirectory = Path.GetDirectoryName(zipContainer.Path); + } + + int changedCount = 0; + libraryContainer.ContentChanged += (s, e) => + { + changedCount++; + }; + + var waitUntil = DateTime.Now.AddSeconds(15); + + var result = Task.Run(() => + { + libraryContainer.Load(); + libraryContainer.Add(new[] { new FileSystemFileItem(filePath) }); + }); + + // Wait for reload + while (DateTime.Now <= waitUntil) + { + if (changedCount > 0) + { + break; + } + + await Task.Delay(200); + } + + // Allow time for invalid additional reloads + await Task.Delay(300); + + Console.WriteLine($"ContentChanged for {containerType.Name}"); + + // Verify Reload is called; + Assert.AreEqual(1, changedCount, $"Expected reload count for {containerType.Name} not hit - container should fire reload event after acquiring content"); + } + } + + onIdlePumpActive = false; + } + + + [Test, Ignore("Not implemented")] + public async Task CalibrationPartsContainerTest() + { + } + + [Test, Ignore("Not implemented")] + public async Task PrintHistoryContainerTest() + { + } + + [Test, Ignore("Not implemented")] + public async Task SqliteLibraryContainerTest() + { + } + + [Test, Ignore("Not implemented")] + public async Task PrintQueueContainerTest() + { + } + + [Test, Ignore("Not implemented")] + public async Task SDCardContainerTest() + { + } + + [Test, Ignore("Not implemented")] + public async Task FileSystemContainerTest() + { + } + + [Test, Ignore("Not implemented")] + public async Task RootLibraryContainerTest() + { + } + + [Test, Ignore("Not implemented")] + public async Task ZipMemoryContainerTest() + { + } + } +} diff --git a/Tests/MatterControl.AutomationTests/MatterControl.AutomationTests.csproj b/Tests/MatterControl.AutomationTests/MatterControl.AutomationTests.csproj index 65af72d93..0867846cb 100644 --- a/Tests/MatterControl.AutomationTests/MatterControl.AutomationTests.csproj +++ b/Tests/MatterControl.AutomationTests/MatterControl.AutomationTests.csproj @@ -70,6 +70,7 @@ + diff --git a/Tests/MatterControl.Tests/MatterControl.Tests.csproj b/Tests/MatterControl.Tests/MatterControl.Tests.csproj index dc26bddab..e399af631 100644 --- a/Tests/MatterControl.Tests/MatterControl.Tests.csproj +++ b/Tests/MatterControl.Tests/MatterControl.Tests.csproj @@ -77,6 +77,7 @@ + diff --git a/Tests/MatterControl.Tests/MatterControl/SliceSettingsFieldTests.cs b/Tests/MatterControl.Tests/MatterControl/SliceSettingsFieldTests.cs index 51df1ce25..740c6b891 100644 --- a/Tests/MatterControl.Tests/MatterControl/SliceSettingsFieldTests.cs +++ b/Tests/MatterControl.Tests/MatterControl/SliceSettingsFieldTests.cs @@ -77,7 +77,6 @@ namespace MatterControl.Tests.MatterControl // Find and validate all UIField types, skipping abstract classes foreach (var fieldType in PluginFinder.FindTypes().Where(fieldType => !fieldType.IsAbstract)) { - if (fieldType.Name == "UIField") { continue; diff --git a/Tests/MatterControl.Tests/RemovedFromProduct.cs b/Tests/MatterControl.Tests/RemovedFromProduct.cs new file mode 100644 index 000000000..559de0516 --- /dev/null +++ b/Tests/MatterControl.Tests/RemovedFromProduct.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using MatterHackers.Agg; +using MatterHackers.Agg.UI; +using MatterHackers.MatterControl; +using MatterHackers.VectorMath; + +namespace MatterControl.Tests +{ + class RemovedFromProduct + { + public static void WriteTestGCodeFile() + { + using (StreamWriter file = new StreamWriter("PerformanceTest.gcode")) + { + //int loops = 150000; + int loops = 150; + int steps = 200; + double radius = 50; + Vector2 center = new Vector2(150, 100); + + file.WriteLine("G28 ; home all axes"); + file.WriteLine("G90 ; use absolute coordinates"); + file.WriteLine("G21 ; set units to millimeters"); + file.WriteLine("G92 E0"); + file.WriteLine("G1 F7800"); + file.WriteLine("G1 Z" + (5).ToString()); + WriteMove(file, center); + + for (int loop = 0; loop < loops; loop++) + { + for (int step = 0; step < steps; step++) + { + Vector2 nextPosition = new Vector2(radius, 0); + nextPosition.Rotate(MathHelper.Tau / steps * step); + WriteMove(file, center + nextPosition); + } + } + + file.WriteLine("M84 ; disable motors"); + } + } + + private static void WriteMove(StreamWriter file, Vector2 center) + { + file.WriteLine("G1 X" + center.x.ToString() + " Y" + center.y.ToString()); + } + + private static void HtmlWindowTest() + { + try + { + SystemWindow htmlTestWindow = new SystemWindow(640, 480); + string htmlContent = ""; + if (true) + { + string releaseNotesFile = Path.Combine("C:\\Users\\lbrubaker\\Downloads", "test1.html"); + htmlContent = File.ReadAllText(releaseNotesFile); + } + else + { + WebClient webClient = new WebClient(); + htmlContent = webClient.DownloadString("http://www.matterhackers.com/s/store?q=pla"); + } + + HtmlWidget content = new HtmlWidget(htmlContent, RGBA_Bytes.Black); + content.AddChild(new GuiWidget() + { + HAnchor = HAnchor.Absolute, + VAnchor = VAnchor.Stretch + }); + content.VAnchor |= VAnchor.Top; + content.BackgroundColor = RGBA_Bytes.White; + htmlTestWindow.AddChild(content); + htmlTestWindow.BackgroundColor = RGBA_Bytes.Cyan; + UiThread.RunOnIdle((state) => + { + htmlTestWindow.ShowAsSystemWindow(); + }, 1); + } + catch + { + int stop = 1; + } + } + } +}