Merge pull request #4628 from jlewin/2.19.7
Add 'Preparing help...' popover when creating index
This commit is contained in:
commit
f3899cefba
7 changed files with 172 additions and 56 deletions
|
|
@ -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")
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<string, HelpArticle> helpArticles)
|
||||
{
|
||||
|
|
@ -150,9 +173,14 @@ namespace MatterControlLib
|
|||
writer.Commit();
|
||||
}
|
||||
|
||||
public IEnumerable<HelpSearchResult> Search(string text)
|
||||
public static IEnumerable<HelpSearchResult> 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);
|
||||
|
||||
|
|
@ -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<SystemWindow>().FirstOrDefault();
|
||||
systemWindow.ShowRightSplitPopup(
|
||||
new MatePoint(searchButton),
|
||||
new MatePoint(searchPanel),
|
||||
borderWidth: 0);
|
||||
var systemWindow = this.Parents<SystemWindow>().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<SystemWindow>().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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,15 +47,16 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
/// <param name="arrowDirection">The direction the popover arrow should point</param>
|
||||
/// <param name="padding">The padding of the control, adjusted internally to account for arrow region</param>
|
||||
/// <param name="notchSize">The size of the arrow notch</param>
|
||||
/// <param name="p2">The arrow offset in x or y given the specified arrow</param>
|
||||
public Popover(ArrowDirection arrowDirection, BorderDouble padding, int notchSize, int p2, bool autoBorderColor = true)
|
||||
/// <param name="arrowOffset">The arrow offset in x or y given the specified arrow</param>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Notch offset. See https://photos.app.goo.gl/YdTiehf6ih7fSoDA9 for point diagram
|
||||
/// </summary>
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -73,13 +73,11 @@ namespace MatterHackers.MatterControl
|
|||
AddGuides();
|
||||
CreateMousePage();
|
||||
CreateKeyBindingsPage();
|
||||
|
||||
searcher = new LuceneHelpSearch();
|
||||
}
|
||||
|
||||
protected override void PerformSearch(string filter)
|
||||
{
|
||||
searchHits = new HashSet<string>(searcher.Search(filter).Select(d => d.Path));
|
||||
searchHits = new HashSet<string>(HelpIndex.Search(filter).Select(d => d.Path));
|
||||
|
||||
base.PerformSearch(filter);
|
||||
}
|
||||
|
|
@ -355,7 +353,6 @@ namespace MatterHackers.MatterControl
|
|||
private TreeNode rootNode;
|
||||
|
||||
private Dictionary<string, HelpArticleTreeNode> nodesByPath = new Dictionary<string, HelpArticleTreeNode>();
|
||||
private LuceneHelpSearch searcher;
|
||||
private IEnumerable<HelpSearchResult> searchResults;
|
||||
private HashSet<string> searchHits;
|
||||
|
||||
|
|
|
|||
31
Program.cs
31
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}")))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue