diff --git a/Constants.cs b/Constants.cs index bbeae08..34b6270 100644 --- a/Constants.cs +++ b/Constants.cs @@ -1,15 +1,24 @@ namespace Flow.Launcher.Plugin.OneNote { - public static class Constants + public static class Icons { - public const string LogoIconPath = "Images/logo.png"; - public const string UnavailableIconPath = "Images/unavailable.png"; - public const string SyncIconPath = "Images/refresh.png"; - public const string RecentIconPath = "Images/recent.png"; - public const string RecentPageIconPath = "Images/recent_page.png"; - public const string WarningLogoPath = "Images/warning.png"; - - public const string StructureKeyword = "nb:\\"; - public const string RecentKeyword = "rcntpgs:"; + + public const string Logo = "Images/logo.png"; + public const string Unavailable = "Images/unavailable.png"; + public const string Sync = "Images/refresh.png"; + public const string Recent = "Images/recent.png"; + public const string RecentPage = "Images/recent_page.png"; + public const string Warning = "Images/warning.png"; + + public const string Section = "Images/section.png"; + public const string Notebook = "Images/notebook.png"; + public const string NewPage = "Images/new_page.png"; + public const string NewSection = "Images/new_section.png"; + public const string NewNotebook = "Images/new_notebook.png"; + } + public static class Keywords + { + public const string NotebookExplorer = "nb:\\"; + public const string RecentPages = "rcntpgs:"; } } \ No newline at end of file diff --git a/Images/new_notebook.png b/Images/new_notebook.png new file mode 100644 index 0000000..dd39b2d Binary files /dev/null and b/Images/new_notebook.png differ diff --git a/Images/new_page.png b/Images/new_page.png new file mode 100644 index 0000000..250eeec Binary files /dev/null and b/Images/new_page.png differ diff --git a/Images/new_section.png b/Images/new_section.png new file mode 100644 index 0000000..ea84278 Binary files /dev/null and b/Images/new_section.png differ diff --git a/Main.cs b/Main.cs index 720cb76..3f36369 100644 --- a/Main.cs +++ b/Main.cs @@ -42,57 +42,68 @@ public List Query(Query query) new Result { Title = "OneNote is not installed.", - IcoPath = Constants.UnavailableIconPath + IcoPath = Icons.Unavailable } }; } if (string.IsNullOrEmpty(query.Search)) { - var results = new List(); - results.Add(new Result + return new List() { - Title = "Search OneNote pages", - SubTitle = $"Type \"{Constants.StructureKeyword}\" to search by notebook structure or select this option", - AutoCompleteText = $"{context.CurrentPluginMetadata.ActionKeyword} {Constants.StructureKeyword}", - IcoPath = Constants.LogoIconPath, - Score = 2000, - Action = c => + new Result { - context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeyword} {Constants.StructureKeyword}"); - return false; + Title = "Search OneNote pages", + SubTitle = $"Type \"{Keywords.NotebookExplorer}\" or select this option to search by notebook structure ", + AutoCompleteText = $"{query.ActionKeyword} {Keywords.NotebookExplorer}", + IcoPath = Icons.Logo, + Score = 2000, + Action = c => + { + context.API.ChangeQuery($"{query.ActionKeyword} {Keywords.NotebookExplorer}"); + return false; + }, }, - }); - results.Add(new Result - { - Title = "See recent pages", - SubTitle = $"Type \"{Constants.RecentKeyword}\" to see last modified pages or select this option", - AutoCompleteText = $"{context.CurrentPluginMetadata.ActionKeyword} {Constants.RecentKeyword}", - IcoPath = Constants.RecentIconPath, - Score = -1000, - Action = c => + new Result { - context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeyword} {Constants.RecentKeyword}"); - return false; + Title = "See recent pages", + SubTitle = $"Type \"{Keywords.RecentPages}\" or select this option to see recently modified pages", + AutoCompleteText = $"{query.ActionKeyword} {Keywords.RecentPages}", + IcoPath = Icons.Recent, + Score = -1000, + Action = c => + { + context.API.ChangeQuery($"{query.ActionKeyword} {Keywords.RecentPages}"); + return false; + }, }, - }); - results.Add(new Result - { - Title = "Open and sync notebooks", - IcoPath = Constants.SyncIconPath, - Score = int.MinValue, - Action = c => + new Result { - OneNoteProvider.PageItems.First().OpenInOneNote(); - OneNoteProvider.NotebookItems.Sync(); - return false; - } - }); - return results; + Title = "New quick note", + IcoPath = Icons.NewPage, + Score = -4000, + Action = c => + { + ScipBeExtensions.CreateAndOpenPage(); + return true; + } + }, + new Result + { + Title = "Open and sync notebooks", + IcoPath = Icons.Sync, + Score = int.MinValue, + Action = c => + { + OneNoteProvider.NotebookItems.OpenAndSync(OneNoteProvider.PageItems.First()); + return false; + } + }, + }; } - if (query.FirstSearch.StartsWith(Constants.RecentKeyword)) + if (query.FirstSearch.StartsWith(Keywords.RecentPages)) { int count = recentPagesCount; - if (query.FirstSearch.Length > Constants.RecentKeyword.Length && int.TryParse(query.FirstSearch[Constants.RecentKeyword.Length..], out int userChosenCount)) + if (query.FirstSearch.Length > Keywords.RecentPages.Length && int.TryParse(query.FirstSearch[Keywords.RecentPages.Length..], out int userChosenCount)) count = userChosenCount; return OneNoteProvider.PageItems.OrderByDescending(pg => pg.LastModified) @@ -101,7 +112,7 @@ public List Query(Query query) { Result result = rc.CreatePageResult(pg); result.SubTitle = $"{GetLastEdited(DateTime.Now - pg.LastModified)}\t{result.SubTitle}"; - result.IcoPath = Constants.RecentPageIconPath; + result.IcoPath = Icons.RecentPage; return result; }) .ToList(); @@ -109,7 +120,7 @@ public List Query(Query query) //Search via notebook structure //NOTE: There is no nested sections i.e. there is nothing for the Section Group in the structure - if (query.FirstSearch.StartsWith(Constants.StructureKeyword)) + if (query.FirstSearch.StartsWith(Keywords.NotebookExplorer)) return notebookExplorer.Explore(query); //Check for invalid start of query i.e. symbols @@ -120,7 +131,7 @@ public List Query(Query query) { Title = "Invalid query", SubTitle = "The first character of the search must be a letter or a digit", - IcoPath = Constants.WarningLogoPath, + IcoPath = Icons.Warning, } }; //Default search @@ -136,13 +147,14 @@ public List Query(Query query) { Title = "No matches found", SubTitle = "Try searching something else, or syncing your notebooks.", - IcoPath = Constants.LogoIconPath, + IcoPath = Icons.Logo, } }; } public List LoadContextMenus(Result selectedResult) { + List results = new List(); switch (selectedResult.ContextData) { case IOneNoteExtNotebook notebook: @@ -152,15 +164,12 @@ public List LoadContextMenus(Result selectedResult) result.ContextData = null; result.Action = c => { - notebook.Sections.First().Pages - .OrderByDescending(pg => pg.LastModified) - .First() - .OpenInOneNote(); - notebook.Sync(); + notebook.OpenAndSync(); lastSelectedNotebook = null; return true; }; - return new List { result }; + results.Add(result); + break; case IOneNoteExtSection section: Result sResult = rc.CreateSectionResult(section, lastSelectedNotebook); sResult.Title = "Open and sync section"; @@ -168,10 +177,7 @@ public List LoadContextMenus(Result selectedResult) sResult.ContextData = null; sResult.Action = c => { - section.Pages.OrderByDescending(pg => pg.LastModified) - .First() - .OpenInOneNote(); - section.Sync(); + section.OpenAndSync(); lastSelectedNotebook = null; lastSelectedSection = null; return true; @@ -181,24 +187,21 @@ public List LoadContextMenus(Result selectedResult) nbResult.SubTitle = lastSelectedNotebook.Name; nbResult.Action = c => { - lastSelectedNotebook.Sections.First().Pages - .OrderByDescending(pg => pg.LastModified) - .First() - .OpenInOneNote(); - lastSelectedNotebook.Sync(); + lastSelectedNotebook.OpenAndSync(); lastSelectedNotebook = null; lastSelectedSection = null; return true; }; - return new List { sResult, nbResult, }; - default: - return new List(); + results.Add(sResult); + results.Add(nbResult); + break; } + return results; } private static string GetLastEdited(TimeSpan diff) { - string lastEdited = "Last editied "; + string lastEdited = "Last edited "; if (PluralCheck(diff.TotalDays, "day", ref lastEdited) || PluralCheck(diff.TotalHours, "hour", ref lastEdited) || PluralCheck(diff.TotalMinutes, "min", ref lastEdited) @@ -206,6 +209,7 @@ private static string GetLastEdited(TimeSpan diff) return lastEdited; else return lastEdited += "Now."; + bool PluralCheck(double totalTime, string timeType, ref string lastEdited) { var roundedTime = (int)Math.Round(totalTime); diff --git a/NotebookExplorer.cs b/NotebookExplorer.cs index c497cd1..4f9ce31 100644 --- a/NotebookExplorer.cs +++ b/NotebookExplorer.cs @@ -15,7 +15,6 @@ public class NotebookExplorer private ResultCreator rc; - private List NoResults => new List(); public NotebookExplorer(PluginInitContext context, OneNotePlugin oneNotePlugin, ResultCreator resultCreator) { @@ -27,79 +26,145 @@ public NotebookExplorer(PluginInitContext context, OneNotePlugin oneNotePlugin, public List Explore(Query query) { string[] searchStrings = query.Search.Split('\\', StringSplitOptions.None); - string searchString; - List highlightData = null; //Could replace switch case with for loop switch (searchStrings.Length) { case 2://Full query for notebook not complete e.g. nb\User Noteb - //Get matching notebooks and create results. - searchString = searchStrings[1]; + //Get matching notebooks and create results. + return GetNotebooks(searchStrings); - if (string.IsNullOrWhiteSpace(searchString)) // Do a normall notebook search - { - LastSelectedNotebook = null; - return OneNoteProvider.NotebookItems.Select(nb => rc.CreateNotebookResult(nb)).ToList(); - } + case 3://Full query for section not complete e.g nb\User Notebook\Happine + return GetSections(searchStrings); - return OneNoteProvider.NotebookItems.Where(nb => - { - if (LastSelectedNotebook != null && nb.ID == LastSelectedNotebook.ID) - return true; + case 4://Searching pages in a section + return GetPages(searchStrings); - return TreeQuery(nb.Name, searchString, out highlightData); - }) - .Select(nb => rc.CreateNotebookResult(nb, highlightData)) - .ToList(); + default: + return new List(); + } + } - case 3://Full query for section not complete e.g nb\User Notebook\Happine - searchString = searchStrings[2]; + private List GetNotebooks(string[] searchStrings) + { + List results = new List(); + string query = searchStrings[1]; - if (!ValidateNotebook(searchStrings[1])) - return NoResults; + if (string.IsNullOrWhiteSpace(query)) // Do a normal notebook search + { + LastSelectedNotebook = null; + results = OneNoteProvider.NotebookItems.Select(nb => rc.CreateNotebookResult(nb)).ToList(); + return results; + } + List highlightData = null; - if (string.IsNullOrWhiteSpace(searchString)) - { - LastSelectedSection = null; - return LastSelectedNotebook.Sections.Where(s => !s.Encrypted) - .Select(s => rc.CreateSectionResult(s, LastSelectedNotebook)) - .ToList(); - } - return LastSelectedNotebook.Sections.Where(s => - { - if(s.Encrypted) - return false; - - if (LastSelectedSection != null && s.ID == LastSelectedSection.ID) - return true; - - return TreeQuery(s.Name, searchString, out highlightData); - }) - .Select(s => rc.CreateSectionResult(s, LastSelectedNotebook, highlightData)) - .ToList(); + results = OneNoteProvider.NotebookItems.Where(nb => + { + if (LastSelectedNotebook != null && nb.ID == LastSelectedNotebook.ID) + return true; - case 4://Searching pages in a section - searchString = searchStrings[3]; + return TreeQuery(nb.Name, query, out highlightData); + }) + .Select(nb => rc.CreateNotebookResult(nb, highlightData)) + .ToList(); - if (!ValidateNotebook(searchStrings[1])) - return NoResults; + if (!results.Any(result => string.Equals(query.Trim(), result.Title, StringComparison.OrdinalIgnoreCase))) + { + results.Add(rc.CreateNewNotebookResult(query)); + } + return results; + } + + private List GetSections(string[] searchStrings) + { + List results = new List(); - if (!ValidateSection(searchStrings[2])) - return NoResults; + string query = searchStrings[2]; - if (string.IsNullOrWhiteSpace(searchString)) - return LastSelectedSection.Pages.Select(pg => rc.CreatePageResult(pg,LastSelectedSection, LastSelectedNotebook)).ToList(); + if (!ValidateNotebook(searchStrings[1])) + return results; - return LastSelectedSection.Pages.Where(pg => TreeQuery(pg.Name, searchString, out highlightData)) - .Select(pg => rc.CreatePageResult(pg,LastSelectedSection, LastSelectedNotebook, highlightData)) + if (string.IsNullOrWhiteSpace(query)) + { + LastSelectedSection = null; + results = LastSelectedNotebook.Sections.Where(s => !s.Encrypted) + .Select(s => rc.CreateSectionResult(s, LastSelectedNotebook)) .ToList(); - default: - return NoResults; + //if no sections show ability to create section + if (!results.Any()) + { + results.Add(new Result + { + Title = "Create section: \"\"", + SubTitle = "No (unencrypted) sections found. Type a valid title to create one", + IcoPath = Icons.NewSection + }); + } + return results; } - + + List highlightData = null; + + results = LastSelectedNotebook.Sections.Where(s => + { + if (s.Encrypted) + return false; + + if (LastSelectedSection != null && s.ID == LastSelectedSection.ID) + return true; + + return TreeQuery(s.Name, query, out highlightData); + }) + .Select(s => rc.CreateSectionResult(s, LastSelectedNotebook, highlightData)) + .ToList(); + if (!results.Any(result => string.Equals(query.Trim(), result.Title, StringComparison.OrdinalIgnoreCase))) + { + results.Add(rc.CreateNewSectionResult(LastSelectedNotebook, query)); + } + return results; + } + + private List GetPages(string[] searchStrings) + { + List results = new List(); + + string query = searchStrings[3]; + + if (!ValidateNotebook(searchStrings[1])) + return results; + + if (!ValidateSection(searchStrings[2])) + return results; + + if (string.IsNullOrWhiteSpace(query)) + { + results = LastSelectedSection.Pages.Select(pg => rc.CreatePageResult(pg, LastSelectedSection, LastSelectedNotebook)).ToList(); + //if no sections show ability to create section + if (!results.Any()) + { + results.Add(new Result + { + Title = "Create page: \"\"", + SubTitle = "No pages found. Type a valid title to create one", + IcoPath = Icons.NewPage + }); + } + return results; + } + + List highlightData = null; + + results = LastSelectedSection.Pages.Where(pg => TreeQuery(pg.Name, query, out highlightData)) + .Select(pg => rc.CreatePageResult(pg, LastSelectedSection, LastSelectedNotebook, highlightData)) + .ToList(); + if (!results.Any(result => string.Equals(query.Trim(), result.Title, StringComparison.OrdinalIgnoreCase))) + { + results.Add(rc.CreateNewPageResult(LastSelectedSection, LastSelectedNotebook, query)); + } + return results; } - + + private bool ValidateNotebook(string notebookName) { if (LastSelectedNotebook == null) diff --git a/OneNoteItemInfo.cs b/OneNoteItemInfo.cs index 9366881..8059ecb 100644 --- a/OneNoteItemInfo.cs +++ b/OneNoteItemInfo.cs @@ -16,8 +16,8 @@ public class OneNoteItemInfo public OneNoteItemInfo(string folderName, string iconName, PluginInitContext context) { icons = new Dictionary(); - iconDirectory = Path.Combine(context.CurrentPluginMetadata.PluginDirectory, "Images/" + folderName); - baseIconPath = Path.Combine(context.CurrentPluginMetadata.PluginDirectory, "Images/" + iconName); + iconDirectory = Path.Combine(context.CurrentPluginMetadata.PluginDirectory, folderName); + baseIconPath = Path.Combine(context.CurrentPluginMetadata.PluginDirectory, iconName); Directory.CreateDirectory(iconDirectory); foreach (var imagePath in Directory.GetFiles(iconDirectory)) { diff --git a/Readme.md b/Readme.md index 0084c18..5c13f5c 100644 --- a/Readme.md +++ b/Readme.md @@ -1,23 +1,39 @@ -Flow.Launcher.Plugin.OneNote -================== +# OneNote for Flow Launcher -A OneNote plugin for the [Flow launcher](https://github.com/Flow-Launcher/Flow.Launcher). +A OneNote plugin for the [Flow launcher](https://github.com/Flow-Launcher/Flow.Launcher), allowing for the ability to quickly access and create notes. +![demo](doc/demo.png) -![demo](./demo.gif) +## Features and Usage -## Usage +| Keyword | Name | Description | +|---------------------------------|------|---------------| +| `` on {OneNote search query} `` | [Default Search](#default-search) | Search OneNote pages, searches page title and content | +| `` on nb:\ `` | [Notebook Explorer](#notebook-explorer) | Navigate notebooks, sections and pages explorer style | +| `` on rcntpgs: `` | [Recent Pages](#recent-pages) | View recently modified pages | -| Keyword | Description | -|---------------------------------|----------------------| -| `` on {onenote search query} `` | Search onenote pages, searches page title and content | -| `` on nb:\ `` | Navigate notebooks, sections and pages explorer style | -| `` on rcntpgs: `` | View recently modified pages | +### Default Search -Acknowledgements -====== +![searchgif](doc/search_pages.gif) -Inpsired by the OneNote plugin for [Powertoy](https://github.com/microsoft/PowerToys/tree/main/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.OneNote) (Its a port with extra features) +### Notebook Explorer + +- Allows for creating notebooks at the default notebook location (set in OneNote) as well as sections and pages at the current path. +- Pressing ⏎ Enter or ⇥ Tab on a notebook or section will auto complete the query. +- Pressing ⇧ Shift + ⏎ Enter on a notebook or section allows you to open it directly in OneNote. +- Encrypted sections are hidden. + +![notebookgif](doc/notebook_explorer.gif) + +### Recent Pages + +Add a number after `` rcntpgs: `` to display that number of recent pages. E.g. `` rcntpgs:10 `` will show the 10 most recently modified pages. + +![recentgif](doc/recent_pages.gif) + +## Acknowledgements + +Inspired by the OneNote plugin for [PowerToys](https://github.com/microsoft/PowerToys/tree/main/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.OneNote) (Its a port with extra features) Icons from [Icons8](https://icons8.com) -Created with [Scipe](https://github.com/scipbe/ScipBe-Common-Office) OneNote tools +Created with [ScipBe](https://github.com/scipbe/ScipBe-Common-Office) OneNote tools diff --git a/ResultCreator.cs b/ResultCreator.cs index a920774..af41f67 100644 --- a/ResultCreator.cs +++ b/ResultCreator.cs @@ -1,5 +1,7 @@ +using System; using System.Collections.Generic; +using System.Linq; using ScipBe.Common.Office.OneNote; namespace Flow.Launcher.Plugin.OneNote @@ -19,9 +21,24 @@ public ResultCreator(PluginInitContext context, OneNotePlugin oneNotePlugin) { this.context = context; this.oneNotePlugin = oneNotePlugin; - notebookInfo = new OneNoteItemInfo("NotebookIcons", "notebook.png", context); - sectionInfo = new OneNoteItemInfo("SectionIcons", "section.png", context); + notebookInfo = new OneNoteItemInfo("Images/NotebookIcons", Icons.Notebook, context); + sectionInfo = new OneNoteItemInfo("Images/SectionIcons", Icons.Section, context); } + + private string GetNicePath(IOneNoteSection section, IOneNoteNotebook notebook, bool isPage) + { + int offset = isPage + ? 4 //"4" is to remove the ".one" from the path + : section.Name.Length + 5; //The "+5" is to remove the ".one" and "/" from the path + var sectionPath = section.Path; + var index = sectionPath.IndexOf(notebook.Name); + var path = sectionPath[index..^offset] + .Replace("/", " > ") + .Replace("\\", " > "); + return path; + } + + public Result CreatePageResult(IOneNoteExtPage page, List highlightingData = null) { return CreatePageResult(page, page.Section, page.Notebook, highlightingData); @@ -29,20 +46,15 @@ public Result CreatePageResult(IOneNoteExtPage page, List highlightingData public Result CreatePageResult(IOneNotePage page, IOneNoteSection section, IOneNoteNotebook notebook, List highlightingData = null) { - var sectionPath = section.Path; - var index = sectionPath.IndexOf(notebook.Name); - var path = sectionPath[index..^4] //"+4" is to remove the ".one" from the path - .Replace("/", " > ") - .Replace("\\", " > "); return new Result { Title = page.Name, - SubTitle = path, TitleToolTip = $"Created: {page.DateTime}\nLast Modified: {page.LastModified}", - SubTitleToolTip = path, - IcoPath = Constants.LogoIconPath, - ContextData = page, TitleHighlightData = highlightingData, + SubTitle = GetNicePath(section, notebook, true), + AutoCompleteText = $"{context.CurrentPluginMetadata.ActionKeyword} {Keywords.NotebookExplorer}{LastSelectedNotebook.Name}\\{section.Name}\\{page.Name}", + IcoPath = Icons.Logo, + ContextData = page, Action = c => { LastSelectedNotebook = null; @@ -55,23 +67,21 @@ public Result CreatePageResult(IOneNotePage page, IOneNoteSection section, IOneN public Result CreateSectionResult(IOneNoteExtSection section, IOneNoteExtNotebook notebook, List highlightData = null) { - var sectionPath = section.Path; - var index = sectionPath.IndexOf(notebook.Name); - var path = sectionPath[index..^(section.Name.Length + 5)] //The "+5" is to remove the ".one" and "/" from the path - .Replace("/", " > ") - .Replace("\\", " > "); - + string path = GetNicePath(section, notebook, false); + string autoCompleteText = $"{context.CurrentPluginMetadata.ActionKeyword} {Keywords.NotebookExplorer}{LastSelectedNotebook.Name}\\{section.Name}\\"; return new Result { Title = section.Name, - SubTitle = path, // + " | " + section.Pages.Count().ToString(), TitleHighlightData = highlightData, + SubTitle = path, + SubTitleToolTip = $"{path} | Number of pages: {section.Pages.Count()}", + AutoCompleteText = autoCompleteText, ContextData = section, IcoPath = sectionInfo.GetIcon(section.Color.Value), Action = c => { LastSelectedSection = section; - context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeyword} {Constants.StructureKeyword}{LastSelectedNotebook.Name}\\{section.Name}\\"); + context.API.ChangeQuery(autoCompleteText); return false; }, }; @@ -79,19 +89,81 @@ public Result CreateSectionResult(IOneNoteExtSection section, IOneNoteExtNoteboo public Result CreateNotebookResult(IOneNoteExtNotebook notebook, List highlightData = null) { + string autoCompleteText = $"{context.CurrentPluginMetadata.ActionKeyword} {Keywords.NotebookExplorer}{notebook.Name}\\"; return new Result { Title = notebook.Name, + TitleToolTip = $"Number of sections: {notebook.Sections.Count()}", TitleHighlightData = highlightData, + AutoCompleteText = autoCompleteText, ContextData = notebook, IcoPath = notebookInfo.GetIcon(notebook.Color.Value), Action = c => { LastSelectedNotebook = notebook; - context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeyword} {Constants.StructureKeyword}{notebook.Name}\\"); + context.API.ChangeQuery(autoCompleteText); return false; }, }; } + + + public Result CreateNewPageResult(IOneNoteSection section, IOneNoteNotebook notebook, string pageTitle) + { + pageTitle = pageTitle.Trim(); + return new Result + { + Title = $"Create page: \"{pageTitle}\"", + SubTitle = $"Path: {GetNicePath(section,notebook,true)}", + IcoPath = Icons.NewPage, + Action = c => + { + ScipBeExtensions.CreateAndOpenPage(LastSelectedSection, pageTitle); + LastSelectedNotebook = null; + LastSelectedSection = null; + return true; + } + }; + } + + public Result CreateNewSectionResult(IOneNoteNotebook notebook, string sectionTitle) + { + sectionTitle = sectionTitle.Trim(); + return new Result + { + Title = $"Create section: \"{sectionTitle}\"", + SubTitle = $"Path: {notebook.Name}", + IcoPath = Icons.NewSection, + Action = c => + { + ScipBeExtensions.CreateAndOpenSection(LastSelectedNotebook,sectionTitle); + context.API.ChangeQuery(context.CurrentPluginMetadata.ActionKeyword); + LastSelectedNotebook = null; + LastSelectedSection = null; + return true; + } + }; + } + + public Result CreateNewNotebookResult(string notebookTitle) + { + notebookTitle = notebookTitle.Trim(); + return new Result + { + Title = $"Create notebook: \"{notebookTitle}\"", + //TitleHighlightData = context.API.FuzzySearch(notebookTitle,title).MatchData, + SubTitle = $"Location: {ScipBeExtensions.GetDefaultNotebookLocation()}", + IcoPath = Icons.NewNotebook, + Action = c => + { + ScipBeExtensions.CreateAndOpenNotebook(context,notebookTitle); + context.API.ChangeQuery(context.CurrentPluginMetadata.ActionKeyword); + LastSelectedNotebook = null; + LastSelectedSection = null; + return true; + } + }; + } + } } \ No newline at end of file diff --git a/ScipBeExtensions.cs b/ScipBeExtensions.cs index 1f56573..ab499d4 100644 --- a/ScipBeExtensions.cs +++ b/ScipBeExtensions.cs @@ -1,4 +1,7 @@ using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; +using Microsoft.Office.Interop.OneNote; using ScipBe.Common.Office.OneNote; using static Flow.Launcher.Plugin.OneNote.ScipBeUtils.Utils; @@ -6,50 +9,102 @@ namespace Flow.Launcher.Plugin.OneNote { public static class ScipBeExtensions { + public static void OpenAndSync(this IOneNoteSection section) + { + CallOneNoteSafely(oneNote => + { + oneNote.NavigateTo(section.ID); + oneNote.SyncHierarchy(section.ID); + }); + } - public static void Sync(this IOneNotePage item) + public static void OpenAndSync(this IOneNoteNotebook notebook) { - CallOneNoteSafely(onenote => onenote.SyncHierarchy(item.ID)); + CallOneNoteSafely(oneNote => + { + oneNote.NavigateTo(notebook.ID); + oneNote.SyncHierarchy(notebook.ID); + }); } - public static void Sync(this IEnumerable items) + public static void OpenAndSync(this IEnumerable notebooks, IOneNotePage lastModifiedPage) { - CallOneNoteSafely(onenote => + CallOneNoteSafely(oneNote => { - foreach (var item in items) + foreach (var notebook in notebooks) { - onenote.SyncHierarchy(item.ID); + oneNote.SyncHierarchy(notebook.ID); } + oneNote.NavigateTo(lastModifiedPage.ID); }); } - public static void Sync(this IOneNoteSection item) + public static string GetDefaultNotebookLocation() { - CallOneNoteSafely(onenote => onenote.SyncHierarchy(item.ID)); + return CallOneNoteSafely(oneNote => + { + oneNote.GetSpecialLocation(SpecialLocation.slDefaultNotebookFolder, out string path); + return path; + }); } - public static void Sync(this IEnumerable items) + public static void CreateAndOpenPage(IOneNoteSection section, string pageTitle) { - CallOneNoteSafely(onenote => + CallOneNoteSafely(oneNote => { - foreach (var item in items) - { - onenote.SyncHierarchy(item.ID); - } + oneNote.GetHierarchy(null, HierarchyScope.hsNotebooks, out string xmlNb); + + XNamespace ns = XDocument.Parse(xmlNb).Root.Name.Namespace; + + oneNote.CreateNewPage(section.ID, out string pageID, NewPageStyle.npsBlankPageWithTitle); + + oneNote.GetPageContent(pageID, out string xml, PageInfo.piBasic); + XDocument doc = XDocument.Parse(xml); + XElement Xtitle = doc.Descendants(ns + "T").First(); + Xtitle.Value = pageTitle; + + oneNote.UpdatePageContent(doc.ToString()); + + oneNote.SyncHierarchy(pageID); + oneNote.NavigateTo(pageID); }); } - public static void Sync(this IOneNoteNotebook item) + public static void CreateAndOpenPage() { - CallOneNoteSafely(onenote => onenote.SyncHierarchy(item.ID)); + CallOneNoteSafely(oneNote => + { + oneNote.GetSpecialLocation(SpecialLocation.slUnfiledNotesSection, out string path); + oneNote.OpenHierarchy(path, null, out string sectionID, CreateFileType.cftNone); + + oneNote.CreateNewPage(sectionID, out string pageID, NewPageStyle.npsDefault); + + oneNote.SyncHierarchy(pageID); + oneNote.NavigateTo(pageID); + }); } - public static void Sync(this IEnumerable items) + + public static void CreateAndOpenSection(this IOneNoteNotebook notebook, string title) { - CallOneNoteSafely(onenote => + CallOneNoteSafely(oneNote => { - foreach (var item in items) - { - onenote.SyncHierarchy(item.ID); - } + oneNote.OpenHierarchy(title + ".one", notebook.ID, out string sectionID, CreateFileType.cftSection); + + oneNote.SyncHierarchy(sectionID); + oneNote.NavigateTo(sectionID); + }); + } + + public static void CreateAndOpenNotebook(PluginInitContext context,string title) + { + CallOneNoteSafely(oneNote => + { + oneNote.GetSpecialLocation(SpecialLocation.slDefaultNotebookFolder, out string path); + + oneNote.OpenHierarchy($"{path}\\{title}", null, out string notebookID, CreateFileType.cftNotebook); + + oneNote.SyncHierarchy(notebookID); + oneNote.NavigateTo(notebookID); }); } + } } diff --git a/ScipBeUtils.cs b/ScipBeUtils.cs index 843b622..55cc40b 100644 --- a/ScipBeUtils.cs +++ b/ScipBeUtils.cs @@ -86,5 +86,25 @@ internal static void CallOneNoteSafely(Action action) } } } + internal static T CallOneNoteSafely(Func action) + { + Application oneNote = null; + try + { + oneNote = TryCatchAndRetry( + () => new Application(), + TimeSpan.FromMilliseconds(100), + 3, + ex => System.Diagnostics.Trace.TraceError(ex.Message)); + return action(oneNote); + } + finally + { + if (oneNote != null) + { + Marshal.ReleaseComObject(oneNote); + } + } + } } } diff --git a/doc/default.png b/doc/default.png new file mode 100644 index 0000000..fce01c6 Binary files /dev/null and b/doc/default.png differ diff --git a/demo.gif b/doc/demo.gif similarity index 100% rename from demo.gif rename to doc/demo.gif diff --git a/doc/demo.png b/doc/demo.png new file mode 100644 index 0000000..26a129d Binary files /dev/null and b/doc/demo.png differ diff --git a/doc/notebook_explorer.gif b/doc/notebook_explorer.gif new file mode 100644 index 0000000..c90a6ad Binary files /dev/null and b/doc/notebook_explorer.gif differ diff --git a/doc/recent_pages.gif b/doc/recent_pages.gif new file mode 100644 index 0000000..74b9b44 Binary files /dev/null and b/doc/recent_pages.gif differ diff --git a/doc/search_pages.gif b/doc/search_pages.gif new file mode 100644 index 0000000..e664d9a Binary files /dev/null and b/doc/search_pages.gif differ diff --git a/plugin.json b/plugin.json index aa97fc8..b3ee8b4 100644 --- a/plugin.json +++ b/plugin.json @@ -4,7 +4,7 @@ "Name": "OneNote", "Description": "Search OneNote notes", "Author": "Odotocodot", - "Version": "1.0.2", + "Version": "1.1.0", "Language": "csharp", "Website": "https://github.com/Odotocodot/Flow.Launcher.Plugin.OneNote", "IcoPath": "Images/logo.png",