From 12d8291a20cadc5067b57aa6063d4091993e6436 Mon Sep 17 00:00:00 2001 From: John Lewin Date: Thu, 20 Jun 2019 22:54:05 -0700 Subject: [PATCH 1/4] Restore Explorer file association support - Issue MatterHackers/MCCentral#5719 Windows Explorer file associations fail to open file --- .../ApplicationView/ApplicationController.cs | 8 +++-- Program.cs | 31 ++++++++++++++----- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/MatterControlLib/ApplicationView/ApplicationController.cs b/MatterControlLib/ApplicationView/ApplicationController.cs index 7cb277d97..d3f8641dc 100644 --- a/MatterControlLib/ApplicationView/ApplicationController.cs +++ b/MatterControlLib/ApplicationView/ApplicationController.cs @@ -2503,7 +2503,8 @@ namespace MatterHackers.MatterControl SourceItem = history.NewPlatingItem() }); - this.OpenWorkspace(workspace); + // Open but no need to save + this.OpenWorkspace(workspace, WorkspacesChangedEventArgs.OperationType.Restore); } } @@ -4068,6 +4069,9 @@ Support and tutorials: { try { + // Initial load builds UI elements, then constructs workspace tabs as they're encountered in RestoreUserTabs() + await applicationController.RestoreUserTabs(); + // Batch startup actions await applicationController.Tasks.Execute( "Finishing Startup".Localize(), @@ -4099,8 +4103,6 @@ Support and tutorials: await applicationController.Tasks.Execute(task.Title, null, task.Action); } - // Initial load builds UI elements, then constructs workspace tabs as they're encountered in RestoreUserTabs() - await applicationController.RestoreUserTabs(); if (ApplicationSettings.Instance.get(UserSettingsKey.ShownWelcomeMessage) != "false") { diff --git a/Program.cs b/Program.cs index a2d93ec3a..5471496d0 100644 --- a/Program.cs +++ b/Program.cs @@ -55,7 +55,9 @@ namespace MatterHackers.MatterControl private static RaygunClient _raygunClient; - private static string mainServiceName = ""; + private static string mainServiceName = "shell"; + + private const string ServiceBaseUri = "net.pipe://localhost/mattercontrol"; [STAThread] public static void Main(string[] args) @@ -105,11 +107,7 @@ namespace MatterHackers.MatterControl return; } - // #endif - var serviceHost = new ServiceHost( - typeof(LocalService), - new Uri[] { new Uri("net.pipe://localhost/mattercontrol") }); - + var serviceHost = new ServiceHost(typeof(LocalService), new[] { new Uri(ServiceBaseUri) }); serviceHost.AddServiceEndpoint(typeof(IMainService), new NetNamedPipeBinding(), mainServiceName); serviceHost.Open(); @@ -118,6 +116,25 @@ namespace MatterHackers.MatterControl string.Join(", ", serviceHost.Description.Endpoints.Select(s => s.ListenUri.AbsoluteUri).ToArray())); } + // If MatterControl isn't running and valid files were shelled, schedule a StartupAction to open the files after load + var shellFiles = args.Where(f => File.Exists(f) && shellFileExtensions.Contains(Path.GetExtension(f).ToLower())); + if (shellFiles.Any()) + { + ApplicationController.StartupActions.Add(new ApplicationController.StartupAction() + { + Title = "Shell Files", + Priority = 0, + Action = () => + { + // Open each shelled file + foreach (string file in shellFiles) + { + ApplicationController.Instance.ShellOpenFile(file); + } + } + }); + } + // Load optional user configuration IConfiguration config = new ConfigurationBuilder() .AddJsonFile("appsettings.json", optional: true) @@ -217,7 +234,7 @@ namespace MatterHackers.MatterControl new ServiceEndpoint( ContractDescription.GetContract(typeof(IMainService)), new NetNamedPipeBinding(), - new EndpointAddress($"net.pipe://localhost/{mainServiceName}"))) + new EndpointAddress($"{ServiceBaseUri}/{mainServiceName}"))) { } From 7608489e09943416172183ef6ec0be00559a7dd9 Mon Sep 17 00:00:00 2001 From: jlewin Date: Fri, 21 Jun 2019 15:33:55 -0700 Subject: [PATCH 2/4] Revise naming, make HelpIndex static --- .../{LuceneHelpSearch.cs => HelpIndex.cs} | 84 ++++++++++++------- .../PartPreviewWindow/SearchPanel.cs | 3 +- MatterControlLib/SetupWizard/HelpTreePanel.cs | 5 +- 3 files changed, 58 insertions(+), 34 deletions(-) rename MatterControlLib/{LuceneHelpSearch.cs => HelpIndex.cs} (64%) diff --git a/MatterControlLib/LuceneHelpSearch.cs b/MatterControlLib/HelpIndex.cs similarity index 64% rename from MatterControlLib/LuceneHelpSearch.cs rename to MatterControlLib/HelpIndex.cs index c5d1fe94a..a4ce01129 100644 --- a/MatterControlLib/LuceneHelpSearch.cs +++ b/MatterControlLib/HelpIndex.cs @@ -1,4 +1,32 @@ - +/* +Copyright (c) 2019, Lars Brubaker, 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.Compression; @@ -22,12 +50,12 @@ using Newtonsoft.Json; namespace MatterControlLib { - public class LuceneHelpSearch + public static class HelpIndex { private static IndexWriter writer; private static StandardAnalyzer analyzer; - static LuceneHelpSearch() + static HelpIndex() { // Ensures index backwards compatibility var AppLuceneVersion = LuceneVersion.LUCENE_48; @@ -35,37 +63,32 @@ namespace MatterControlLib var indexLocation = System.IO.Path.Combine(ApplicationDataStorage.Instance.ApplicationTempDataPath, "LuceneIndex"); System.IO.Directory.CreateDirectory(indexLocation); - var dir = FSDirectory.Open(indexLocation); - // create an analyzer to process the text analyzer = new StandardAnalyzer(AppLuceneVersion); // create an index writer - var indexConfig = new IndexWriterConfig(AppLuceneVersion, analyzer); - - writer = new IndexWriter(dir, indexConfig); - - // If the index lacks a reasonable number of documents, rebuild it from the zip file - if (writer.MaxDoc < 10) - { - ApplicationController.Instance.Tasks.Execute( - "Preparing help index".Localize(), - null, - (progress, cancellationToken) => - { - string relativePath = System.IO.Path.Combine("OemSettings", "help-docs.zip"); - - IndexZipFile(relativePath, progress, cancellationToken); - - return Task.CompletedTask; - }); - } + writer = new IndexWriter( + FSDirectory.Open(indexLocation), + new IndexWriterConfig(AppLuceneVersion, analyzer)); } - public LuceneHelpSearch() + public static bool IndexExists => writer.MaxDoc > 0; + + public static Task RebuildIndex() { - } + // If the index lacks a reasonable number of documents, rebuild it from the zip file + return ApplicationController.Instance.Tasks.Execute( + "Preparing help index".Localize(), + null, + (progress, cancellationToken) => + { + string relativePath = System.IO.Path.Combine("OemSettings", "help-docs.zip"); + IndexZipFile(relativePath, progress, cancellationToken); + + return Task.CompletedTask; + }); + } private static void ProcessHelpTree(HelpArticle context, Dictionary helpArticles) { @@ -150,9 +173,14 @@ namespace MatterControlLib writer.Commit(); } - public IEnumerable Search(string text) + public static IEnumerable Search(string text) { - //var parser = new QueryParser(LuceneVersion.LUCENE_48, "body", analyzer); + // If the index lacks a reasonable number of documents, rebuild it from the zip file + if (writer.MaxDoc < 10) + { + RebuildIndex(); + } + var parser = new MultiFieldQueryParser(LuceneVersion.LUCENE_48, new[] { "body", "name" }, analyzer); var query = parser.Parse(text); diff --git a/MatterControlLib/PartPreviewWindow/SearchPanel.cs b/MatterControlLib/PartPreviewWindow/SearchPanel.cs index 334ffc17b..8f8cb1b94 100644 --- a/MatterControlLib/PartPreviewWindow/SearchPanel.cs +++ b/MatterControlLib/PartPreviewWindow/SearchPanel.cs @@ -87,8 +87,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow var searchHits = await Task.Run(() => { - var searcher = new LuceneHelpSearch(); - return searcher.Search(searchBox.searchInput.Text); + return HelpIndex.Search(searchBox.searchInput.Text); }); searchResults.CloseAllChildren(); diff --git a/MatterControlLib/SetupWizard/HelpTreePanel.cs b/MatterControlLib/SetupWizard/HelpTreePanel.cs index 35e1d869a..8c75409ab 100644 --- a/MatterControlLib/SetupWizard/HelpTreePanel.cs +++ b/MatterControlLib/SetupWizard/HelpTreePanel.cs @@ -73,13 +73,11 @@ namespace MatterHackers.MatterControl AddGuides(); CreateMousePage(); CreateKeyBindingsPage(); - - searcher = new LuceneHelpSearch(); } protected override void PerformSearch(string filter) { - searchHits = new HashSet(searcher.Search(filter).Select(d => d.Path)); + searchHits = new HashSet(HelpIndex.Search(filter).Select(d => d.Path)); base.PerformSearch(filter); } @@ -355,7 +353,6 @@ namespace MatterHackers.MatterControl private TreeNode rootNode; private Dictionary nodesByPath = new Dictionary(); - private LuceneHelpSearch searcher; private IEnumerable searchResults; private HashSet searchHits; From 903a737db972df4b6f7986c08fd234a5b92bdeef Mon Sep 17 00:00:00 2001 From: jlewin Date: Fri, 21 Jun 2019 15:34:39 -0700 Subject: [PATCH 3/4] Rename p2 to arrowOffset, rebuild shape in ArrowOffset setter --- MatterControlLib/PartPreviewWindow/Popover.cs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/MatterControlLib/PartPreviewWindow/Popover.cs b/MatterControlLib/PartPreviewWindow/Popover.cs index 1df1d4d2f..03459e69a 100644 --- a/MatterControlLib/PartPreviewWindow/Popover.cs +++ b/MatterControlLib/PartPreviewWindow/Popover.cs @@ -47,15 +47,16 @@ namespace MatterHackers.MatterControl.PartPreviewWindow /// The direction the popover arrow should point /// The padding of the control, adjusted internally to account for arrow region /// The size of the arrow notch - /// The arrow offset in x or y given the specified arrow - public Popover(ArrowDirection arrowDirection, BorderDouble padding, int notchSize, int p2, bool autoBorderColor = true) + /// The arrow offset in x or y given the specified arrow + public Popover(ArrowDirection arrowDirection, BorderDouble padding, int notchSize, int arrowOffset, bool autoBorderColor = true) : base (FlowDirection.TopToBottom) { this.originalPadding = padding; this.NotchSize = notchSize; this.ArrowDirection = arrowDirection; - this.ArrowOffset = p2; this.autoBorderColor = autoBorderColor; + + _arrowOffset = arrowOffset; } public virtual Color TagColor @@ -115,10 +116,23 @@ namespace MatterHackers.MatterControl.PartPreviewWindow tabStroke = new Stroke(tabShape); } + private int _arrowOffset; + /// /// Notch offset. See https://photos.app.goo.gl/YdTiehf6ih7fSoDA9 for point diagram /// - public int ArrowOffset { get; protected set; } + public int ArrowOffset + { + get => _arrowOffset; + set + { + if (_arrowOffset != value) + { + _arrowOffset = value; + this.RebuildShape(); + } + } + } private bool autoBorderColor; private ArrowDirection _arrow; From dccc3c0fea05a5bc1147593613b763ae47120fef Mon Sep 17 00:00:00 2001 From: jlewin Date: Fri, 21 Jun 2019 15:35:35 -0700 Subject: [PATCH 4/4] Add 'Preparing help...' popover when creating index - Issue MatterHackers/MCCentral#5715 Show 'Waiting for Results' --- .../PartPreviewWindow/MainViewWidget.cs | 75 +++++++++++++++++-- 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/MatterControlLib/PartPreviewWindow/MainViewWidget.cs b/MatterControlLib/PartPreviewWindow/MainViewWidget.cs index cef409411..d3b86b9fd 100644 --- a/MatterControlLib/PartPreviewWindow/MainViewWidget.cs +++ b/MatterControlLib/PartPreviewWindow/MainViewWidget.cs @@ -32,6 +32,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using MatterControlLib; using MatterHackers.Agg; using MatterHackers.Agg.Platform; using MatterHackers.Agg.UI; @@ -83,18 +84,76 @@ namespace MatterHackers.MatterControl.PartPreviewWindow searchButton.Click += SearchButton_Click; extensionArea.AddChild(searchButton); - void SearchButton_Click(object sender, EventArgs e) + async void SearchButton_Click(object sender, EventArgs e) { if (searchPanel == null) { - searchPanel = new SearchPanel(this.TabControl, searchButton, theme); - searchPanel.Closed += SearchPanel_Closed; + void ShowSearchPanel() + { + searchPanel = new SearchPanel(this.TabControl, searchButton, theme); + searchPanel.Closed += SearchPanel_Closed; - var systemWindow = this.Parents().FirstOrDefault(); - systemWindow.ShowRightSplitPopup( - new MatePoint(searchButton), - new MatePoint(searchPanel), - borderWidth: 0); + var systemWindow = this.Parents().FirstOrDefault(); + systemWindow.ShowRightSplitPopup( + new MatePoint(searchButton), + new MatePoint(searchPanel), + borderWidth: 0); + } + + if (HelpIndex.IndexExists) + { + ShowSearchPanel(); + } + else + { + searchButton.Enabled = false; + + try + { + // Show popover + var popover = new Popover(ArrowDirection.Up, 7, 5, 0) + { + TagColor = theme.AccentMimimalOverlay + }; + + popover.AddChild(new TextWidget("Preparing help".Localize() + "...", pointSize: theme.DefaultFontSize - 1, textColor: theme.TextColor)); + + popover.ArrowOffset = (int)(popover.Width - (searchButton.Width / 2)); + + this.Parents().FirstOrDefault().ShowPopover( + new MatePoint(searchButton) + { + Mate = new MateOptions(MateEdge.Right, MateEdge.Bottom), + AltMate = new MateOptions(MateEdge.Right, MateEdge.Bottom), + Offset = new RectangleDouble(12, 0, 12, 0) + }, + new MatePoint(popover) + { + Mate = new MateOptions(MateEdge.Right, MateEdge.Top), + AltMate = new MateOptions(MateEdge.Left, MateEdge.Bottom) + }); + + await Task.Run(async () => + { + // Start index generation + await HelpIndex.RebuildIndex(); + + UiThread.RunOnIdle(() => + { + // Close popover + popover.Close(); + + // Continue to original task + ShowSearchPanel(); + }); + }); + } + catch + { + } + + searchButton.Enabled = true; + } } else {