diff --git a/MatterControlLib/ApplicationView/Config/BedConfig.cs b/MatterControlLib/ApplicationView/Config/BedConfig.cs index 437837bc0..ba3b7eac9 100644 --- a/MatterControlLib/ApplicationView/Config/BedConfig.cs +++ b/MatterControlLib/ApplicationView/Config/BedConfig.cs @@ -682,7 +682,7 @@ namespace MatterHackers.MatterControl { UiThread.RunOnIdle(() => { - // we need to ask for a destination + // we need to ask for a destination DialogWindow.Show( new SaveAsPage( (container, newName) => diff --git a/MatterControlLib/Library/Interfaces/LibraryExtensionMethods.cs b/MatterControlLib/Library/Interfaces/LibraryExtensionMethods.cs index c53490fbd..1a87fbbb2 100644 --- a/MatterControlLib/Library/Interfaces/LibraryExtensionMethods.cs +++ b/MatterControlLib/Library/Interfaces/LibraryExtensionMethods.cs @@ -30,13 +30,18 @@ either expressed or implied, of the FreeBSD Project. using System; using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Text; using System.Threading.Tasks; +using MatterHackers.Agg; using MatterHackers.DataConverters3D; using MatterHackers.Localizations; +using MatterHackers.MatterControl.CustomWidgets; +using Newtonsoft.Json; namespace MatterHackers.MatterControl.Library { - public static class LibraryExtensionMethods + public static class LibraryExtensionMethods { public static async Task CreateContent(this ILibraryItem libraryItem, Action progressReporter) { @@ -126,6 +131,52 @@ namespace MatterHackers.MatterControl.Library } } + public static string GetPath(this ILibraryContainer currentContainer) + { + return string.Join("/", currentContainer.AncestorsAndSelf().Reverse().Select(c => c.Name)); + } + + private static string GetDBKey(ILibraryContainer activeContainer) + { + var idFromPath = activeContainer.GetPath(); + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(idFromPath))) + { + var sha1 = HashGenerator.ComputeSHA1(stream); + return $"library-{sha1}"; + } + } + + public static LibraryViewState GetUserView(this ILibraryContainer currentContainer) + { + string dbKey = GetDBKey(currentContainer); + + try + { + string storedJson = UserSettings.Instance.get(dbKey); + if (!string.IsNullOrWhiteSpace(storedJson)) + { + return JsonConvert.DeserializeObject(storedJson); + } + } + catch (Exception ex) + { + Console.WriteLine($"Error loading view {currentContainer.Name}: {ex.Message}"); + } + + return null; + } + + public static void PersistUserView(this ILibraryContainer currentContainer, LibraryViewState userView) + { + string dbKey = GetDBKey(currentContainer); + + // Store + string json = JsonConvert.SerializeObject(userView); + + UserSettings.Instance.set(dbKey, json); + } + public static void Add(this Dictionary list, IEnumerable extensions, IContentProvider provider) { foreach (var extension in extensions) diff --git a/MatterControlLib/Library/Interfaces/LibraryViewState.cs b/MatterControlLib/Library/Interfaces/LibraryViewState.cs new file mode 100644 index 000000000..d78ee60ec --- /dev/null +++ b/MatterControlLib/Library/Interfaces/LibraryViewState.cs @@ -0,0 +1,40 @@ +/* +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 MatterHackers.MatterControl.Library.Widgets; + +namespace MatterHackers.MatterControl.Library +{ + public class LibraryViewState + { + public PrintLibraryWidget.ListViewModes ViewMode { get; set; } + + public LibrarySortBehavior SortBehavior { get; set; } + } +} diff --git a/MatterControlLib/Library/Widgets/LibraryWidget.cs b/MatterControlLib/Library/Widgets/LibraryWidget.cs index 38b7f5d2b..3592882c0 100644 --- a/MatterControlLib/Library/Widgets/LibraryWidget.cs +++ b/MatterControlLib/Library/Widgets/LibraryWidget.cs @@ -248,21 +248,21 @@ namespace MatterHackers.MatterControl.Library.Widgets popupMenu.CreateBoolMenuItem( "Date Created".Localize(), () => libraryView.ActiveSort.HasFlag(SortKey.CreatedDate), - (v) => libraryView.ActiveSort = SortKey.CreatedDate, + (v) => libraryView.SetUserSort(SortKey.CreatedDate), useRadioStyle: false, siblingRadioButtonList: siblingList); popupMenu.CreateBoolMenuItem( "Date Modified".Localize(), () => libraryView.ActiveSort.HasFlag(SortKey.ModifiedDate), - (v) => libraryView.ActiveSort = SortKey.ModifiedDate, + (v) => libraryView.SetUserSort(SortKey.ModifiedDate), useRadioStyle: false, siblingRadioButtonList: siblingList); popupMenu.CreateBoolMenuItem( "Name".Localize(), () => libraryView.ActiveSort.HasFlag(SortKey.Name), - (v) => libraryView.ActiveSort = SortKey.Name, + (v) => libraryView.SetUserSort(SortKey.Name), useRadioStyle: false, siblingRadioButtonList: siblingList); @@ -273,14 +273,14 @@ namespace MatterHackers.MatterControl.Library.Widgets popupMenu.CreateBoolMenuItem( "Ascending".Localize(), () => libraryView.Ascending, - (v) => libraryView.Ascending = true, + (v) => libraryView.SetUserSort(ascending: true), useRadioStyle: false, siblingRadioButtonList: siblingList); popupMenu.CreateBoolMenuItem( "Descending".Localize(), () => !libraryView.Ascending, - (v) => libraryView.Ascending = false, + (v) => libraryView.SetUserSort(ascending: false), useRadioStyle: false, siblingRadioButtonList: siblingList); @@ -325,11 +325,8 @@ namespace MatterHackers.MatterControl.Library.Widgets popupMenu.CreateBoolMenuItem( "View List".Localize(), () => ApplicationController.Instance.ViewState.LibraryViewMode == ListViewModes.RowListView, - (isChecked) => - { - ApplicationController.Instance.ViewState.LibraryViewMode = ListViewModes.RowListView; - listView.ListContentView = new RowListView(theme); - listView.Reload().ConfigureAwait(false); + (isChecked) => { + listView.SetContentView(ListViewModes.RowListView); }, useRadioStyle: false, siblingRadioButtonList: siblingList); @@ -339,9 +336,7 @@ namespace MatterHackers.MatterControl.Library.Widgets () => ApplicationController.Instance.ViewState.LibraryViewMode == ListViewModes.IconListView18, (isChecked) => { - ApplicationController.Instance.ViewState.LibraryViewMode = ListViewModes.IconListView18; - listView.ListContentView = new IconListView(theme, 18); - listView.Reload().ConfigureAwait(false); + listView.SetContentView(ListViewModes.IconListView18); }, useRadioStyle: false, siblingRadioButtonList: siblingList); @@ -351,9 +346,7 @@ namespace MatterHackers.MatterControl.Library.Widgets () => ApplicationController.Instance.ViewState.LibraryViewMode == ListViewModes.IconListView70, (isChecked) => { - ApplicationController.Instance.ViewState.LibraryViewMode = ListViewModes.IconListView70; - listView.ListContentView = new IconListView(theme, 70); - listView.Reload().ConfigureAwait(false); + listView.SetContentView(ListViewModes.IconListView70); }, useRadioStyle: false, siblingRadioButtonList: siblingList); @@ -363,9 +356,7 @@ namespace MatterHackers.MatterControl.Library.Widgets () => ApplicationController.Instance.ViewState.LibraryViewMode == ListViewModes.IconListView, (isChecked) => { - ApplicationController.Instance.ViewState.LibraryViewMode = ListViewModes.IconListView; - listView.ListContentView = new IconListView(theme); - listView.Reload().ConfigureAwait(false); + listView.SetContentView(ListViewModes.IconListView); }, useRadioStyle: false, siblingRadioButtonList: siblingList); @@ -375,9 +366,7 @@ namespace MatterHackers.MatterControl.Library.Widgets () => ApplicationController.Instance.ViewState.LibraryViewMode == ListViewModes.IconListView256, (isChecked) => { - ApplicationController.Instance.ViewState.LibraryViewMode = ListViewModes.IconListView256; - listView.ListContentView = new IconListView(theme, 256); - listView.Reload().ConfigureAwait(false); + listView.SetContentView(ListViewModes.IconListView256); }, useRadioStyle: false, siblingRadioButtonList: siblingList); diff --git a/MatterControlLib/Library/Widgets/ListView/LibraryListView.cs b/MatterControlLib/Library/Widgets/ListView/LibraryListView.cs index 42eb1810f..3f5a793bf 100644 --- a/MatterControlLib/Library/Widgets/ListView/LibraryListView.cs +++ b/MatterControlLib/Library/Widgets/ListView/LibraryListView.cs @@ -30,8 +30,10 @@ either expressed or implied, of the FreeBSD Project. using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.IO; using System.Linq; +using System.Text; using System.Threading.Tasks; using Markdig.Agg; using MatterHackers.Agg; @@ -39,9 +41,12 @@ using MatterHackers.Agg.Image; using MatterHackers.Agg.UI; using MatterHackers.Localizations; using MatterHackers.MatterControl.Library; +using MatterHackers.MatterControl.Library.Widgets; using MatterHackers.MatterControl.PartPreviewWindow; using MatterHackers.MatterControl.PrintQueue; using MatterHackers.VectorMath; +using static MatterHackers.MatterControl.CustomWidgets.LibraryListView; +using static MatterHackers.MatterControl.Library.Widgets.PrintLibraryWidget; namespace MatterHackers.MatterControl.CustomWidgets { @@ -126,12 +131,26 @@ namespace MatterHackers.MatterControl.CustomWidgets { var activeContainer = e.ActiveContainer; - // Anytime the container changes, - Type targetType = activeContainer?.DefaultView; - if (targetType != null + if (activeContainer.DefaultSort != null) + { + this.ActiveSort = activeContainer.DefaultSort.SortKey; + this.Ascending = activeContainer.DefaultSort.Ascending; + } + + // If a container level view override is active, but the container is not, restore the original view + if (stashedContentView != null + && activeContainer.ViewOverride == null) + { + // Switch back to the original view + stashedContentView.ClearRemovedFlag(); + this.ListContentView = stashedContentView; + stashedContentView = null; + } + + if (activeContainer?.ViewOverride is Type targetType && targetType != this.ListContentView.GetType()) { - // If no original view is stored in stashedContentView then store a reference before the switch + // Stash the active view while the container level override is in place if (stashedContentView == null) { stashedContentView = this.ListContentView; @@ -143,35 +162,15 @@ namespace MatterHackers.MatterControl.CustomWidgets this.ListContentView = targetView; } } - else if (stashedContentView != null) + else if (activeContainer.GetUserView() is LibraryViewState userView) { - // Switch back to the original view - stashedContentView.ClearRemovedFlag(); - this.ListContentView = stashedContentView; - stashedContentView = null; - } - - if (activeContainer.DefaultSort != null) - { - if (stashedSortOrder == null) + if (userView.ViewMode != ApplicationController.Instance.ViewState.LibraryViewMode) { - stashedSortOrder = new LibrarySortBehavior() - { - SortKey = this.ActiveSort, - Ascending = this.Ascending - }; + this.SetContentView(userView.ViewMode, userDriven: false); } - this.ActiveSort = activeContainer.DefaultSort.SortKey; - this.Ascending = activeContainer.DefaultSort.Ascending; - } - else if (stashedSortOrder != null - && (stashedSortOrder.SortKey != this.ActiveSort - || stashedSortOrder.Ascending != this.Ascending)) - { - this.ActiveSort = stashedSortOrder.SortKey; - this.Ascending = stashedSortOrder.Ascending; - stashedSortOrder = null; + this.ActiveSort = userView.SortBehavior.SortKey; + this.Ascending = userView.SortBehavior.Ascending; } await DisplayContainerContent(activeContainer); @@ -192,7 +191,6 @@ namespace MatterHackers.MatterControl.CustomWidgets public IEnumerable Items => items; private SortKey _activeSort = SortKey.Name; - private LibrarySortBehavior stashedSortOrder; public SortKey ActiveSort { @@ -225,6 +223,71 @@ namespace MatterHackers.MatterControl.CustomWidgets } } + public void SetUserSort(SortKey sortKey) + { + this.ActiveSort = sortKey; + this.PersistUserView(); + } + + public void SetUserSort(bool ascending) + { + this.Ascending = true; + this.PersistUserView(); + } + + public void SetContentView(PrintLibraryWidget.ListViewModes viewMode, bool userDriven = true) + { + ApplicationController.Instance.ViewState.LibraryViewMode = viewMode; + + switch (viewMode) + { + case PrintLibraryWidget.ListViewModes.RowListView: + this.ListContentView = new RowListView(theme); + break; + + case PrintLibraryWidget.ListViewModes.IconListView18: + this.ListContentView = new IconListView(theme, 18); + break; + + case PrintLibraryWidget.ListViewModes.IconListView70: + this.ListContentView = new IconListView(theme, 70); + break; + + case PrintLibraryWidget.ListViewModes.IconListView256: + this.ListContentView = new IconListView(theme, 256); + break; + + case PrintLibraryWidget.ListViewModes.IconListView: + default: + if (viewMode != PrintLibraryWidget.ListViewModes.IconListView) + { + Debugger.Break(); // Unknown/unexpected value + } + + this.ListContentView = new IconListView(theme); + break; + } + + if (userDriven) + { + this.PersistUserView(); + this.Reload().ConfigureAwait(false); + } + } + + public void PersistUserView() + { + this.ActiveContainer.PersistUserView(new LibraryViewState() + { + ViewMode = ApplicationController.Instance.ViewState.LibraryViewMode, + SortBehavior = new LibrarySortBehavior() + { + SortKey = _activeSort, + Ascending = _ascending, + } + }); + } + private void ApplySort() { this.Reload().ConfigureAwait(false);