mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-03 10:56:36 +01:00
Compare commits
1 Commits
peiyao/tes
...
dev/vanzue
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fe2bb6dc1 |
2
.github/actions/spell-check/excludes.txt
vendored
2
.github/actions/spell-check/excludes.txt
vendored
@@ -92,7 +92,6 @@
|
||||
^\.github/actions/spell-check/
|
||||
^\.gitmodules$
|
||||
^\Q.github/workflows/spelling2.yml\E$
|
||||
^\Q.pipelines/272MSSharedLibSN2048.snk\E$
|
||||
^\Q.pipelines/ESRPSigning_core.json\E$
|
||||
^\Qdoc/devdocs/localization.md\E$
|
||||
^\Qsrc/common/ManagedCommon/ColorFormatHelper.cs\E$
|
||||
@@ -121,7 +120,6 @@
|
||||
^src/modules/MouseWithoutBorders/App/Form/.*\.resx$
|
||||
^src/modules/MouseWithoutBorders/App/Helper/.*\.resx$
|
||||
^src/modules/previewpane/UnitTests-MarkdownPreviewHandler/HelperFiles/MarkdownWithHTMLImageTag\.txt$
|
||||
^src/modules/ZoomIt/ZoomIt/ZoomIt\.idc$
|
||||
^src/Monaco/
|
||||
^src/common/sysinternals/Eula/
|
||||
^tools/Verification scripts/Check preview handler registration\.ps1$
|
||||
|
||||
21
.github/actions/spell-check/expect.txt
vendored
21
.github/actions/spell-check/expect.txt
vendored
@@ -328,6 +328,7 @@ DEFAULTTONULL
|
||||
DEFAULTTOPRIMARY
|
||||
DEFERERASE
|
||||
DEFPUSHBUTTON
|
||||
DEFT
|
||||
deinitialization
|
||||
DELA
|
||||
DELETEDKEYIMAGE
|
||||
@@ -669,6 +670,7 @@ IBeam
|
||||
icf
|
||||
ICONERROR
|
||||
ICONLOCATION
|
||||
idc
|
||||
IDCANCEL
|
||||
IDD
|
||||
idk
|
||||
@@ -679,6 +681,7 @@ IDR
|
||||
IDXGI
|
||||
ietf
|
||||
IEXPLORE
|
||||
iextn
|
||||
IFACEMETHOD
|
||||
IFACEMETHODIMP
|
||||
IFile
|
||||
@@ -717,6 +720,7 @@ INPUTMOUSE
|
||||
INPUTSINK
|
||||
INPUTTYPE
|
||||
INSTALLDESKTOPSHORTCUT
|
||||
INSTALLDIR
|
||||
installdir
|
||||
INSTALLFOLDER
|
||||
INSTALLFOLDERTOBOOTSTRAPPERINSTALLFOLDER
|
||||
@@ -808,6 +812,7 @@ LMENU
|
||||
lnks
|
||||
LOADFROMFILE
|
||||
LOBYTE
|
||||
localappdata
|
||||
LOCALDISPLAY
|
||||
localpackage
|
||||
LOCALSYSTEM
|
||||
@@ -972,6 +977,7 @@ msrc
|
||||
msstore
|
||||
mst
|
||||
msvcp
|
||||
msvsmon
|
||||
MTND
|
||||
MULTIPLEUSE
|
||||
multizone
|
||||
@@ -1278,6 +1284,7 @@ pstm
|
||||
PStr
|
||||
pstream
|
||||
pstrm
|
||||
pswd
|
||||
PSYSTEM
|
||||
psz
|
||||
ptb
|
||||
@@ -1469,12 +1476,16 @@ SHELLDLL
|
||||
shellex
|
||||
SHELLEXECUTEINFO
|
||||
SHELLEXECUTEINFOW
|
||||
SHELLEXTENSION
|
||||
SHELLICONSIZE
|
||||
SHELLNEWVALUE
|
||||
SHFILEINFO
|
||||
SHFILEOPSTRUCT
|
||||
SHGDN
|
||||
SHGDNF
|
||||
SHGFI
|
||||
SHGFIICON
|
||||
SHGFILARGEICON
|
||||
SHIL
|
||||
shinfo
|
||||
shlwapi
|
||||
@@ -1508,6 +1519,7 @@ siex
|
||||
sigdn
|
||||
SIGNINGSCENARIO
|
||||
signtool
|
||||
Signtool
|
||||
SINGLEKEY
|
||||
sipolicy
|
||||
SIZEBOX
|
||||
@@ -1683,6 +1695,7 @@ TLayout
|
||||
tlb
|
||||
tlbimp
|
||||
tlc
|
||||
TGM
|
||||
TNP
|
||||
Toolhelp
|
||||
toolkitconverters
|
||||
@@ -1770,6 +1783,7 @@ uxtheme
|
||||
vabdq
|
||||
validmodulename
|
||||
valuegenerator
|
||||
VARENUM
|
||||
variantassignment
|
||||
vcamp
|
||||
VCENTER
|
||||
@@ -1989,6 +2003,11 @@ CLSCTXINPROCALL
|
||||
IIDI
|
||||
irow
|
||||
lcid
|
||||
OTHERUNZOOM
|
||||
OTHERZOOM
|
||||
PARENTCLOSING
|
||||
PARENTOPENING
|
||||
ppwsz
|
||||
rguid
|
||||
VARTYPE
|
||||
SCROLLCHILDREN
|
||||
VARTYPE
|
||||
2
.github/actions/spell-check/patterns.txt
vendored
2
.github/actions/spell-check/patterns.txt
vendored
@@ -243,4 +243,4 @@ Process Process
|
||||
|
||||
# ZoomIt menu items with accelerator keys
|
||||
E&xit
|
||||
St&yle
|
||||
St&yle
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
pwsh: true
|
||||
ScriptType: InlineScript
|
||||
Inline: |-
|
||||
$AzToken = (Get-AzAccessToken -AsSecureString -ResourceUrl api://30471ccf-0966-45b9-a979-065dbedb24c1).Token | ConvertFrom-SecureString -AsPlainText
|
||||
$AzToken = (Get-AzAccessToken -ResourceUrl api://30471ccf-0966-45b9-a979-065dbedb24c1).Token
|
||||
Write-Host "##vso[task.setvariable variable=SymbolAccessToken;issecret=true]$AzToken"
|
||||
|
||||
|
||||
|
||||
@@ -72,57 +72,9 @@ $returnList = [System.Collections.Generic.HashSet[string]]($totalList) -join "`r
|
||||
|
||||
Write-Host $returnList
|
||||
|
||||
# Extract the current package list from NOTICE.md
|
||||
$noticePattern = "## NuGet Packages used by PowerToys\s*((?:\r?\n- .+)+)"
|
||||
$noticeMatch = [regex]::Match($noticeFile, $noticePattern)
|
||||
|
||||
if ($noticeMatch.Success) {
|
||||
$currentNoticePackageList = $noticeMatch.Groups[1].Value.Trim()
|
||||
} else {
|
||||
Write-Warning "Warning: Could not find 'NuGet Packages used by PowerToys' section in NOTICE.md"
|
||||
$currentNoticePackageList = ""
|
||||
}
|
||||
|
||||
if (!$noticeFile.Trim().EndsWith($returnList.Trim()))
|
||||
{
|
||||
Write-Host -ForegroundColor Red "Notice.md does not match NuGet list."
|
||||
|
||||
# Show detailed differences
|
||||
$generatedPackages = $returnList -split "`r`n|`n" | Where-Object { $_.Trim() -ne "" } | Sort-Object
|
||||
$noticePackages = $currentNoticePackageList -split "`r`n|`n" | Where-Object { $_.Trim() -ne "" } | ForEach-Object { $_.Trim() } | Sort-Object
|
||||
|
||||
Write-Host ""
|
||||
Write-Host -ForegroundColor Cyan "=== DETAILED DIFFERENCE ANALYSIS ==="
|
||||
Write-Host ""
|
||||
|
||||
# Find packages in proj file list but not in NOTICE.md
|
||||
$missingFromNotice = $generatedPackages | Where-Object { $noticePackages -notcontains $_ }
|
||||
if ($missingFromNotice.Count -gt 0) {
|
||||
Write-Host -ForegroundColor Red "MissingFromNotice:"
|
||||
foreach ($pkg in $missingFromNotice) {
|
||||
Write-Host -ForegroundColor Red " $pkg"
|
||||
}
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Find packages in NOTICE.md but not in proj file list
|
||||
$extraInNotice = $noticePackages | Where-Object { $generatedPackages -notcontains $_ }
|
||||
if ($extraInNotice.Count -gt 0) {
|
||||
Write-Host -ForegroundColor Yellow "ExtraInNotice:"
|
||||
foreach ($pkg in $extraInNotice) {
|
||||
Write-Host -ForegroundColor Yellow " $pkg"
|
||||
}
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Show counts for summary
|
||||
Write-Host -ForegroundColor Cyan "Summary:"
|
||||
Write-Host " Proj file list has $($generatedPackages.Count) packages"
|
||||
Write-Host " NOTICE.md has $($noticePackages.Count) packages"
|
||||
Write-Host " MissingFromNotice: $($missingFromNotice.Count) packages"
|
||||
Write-Host " ExtraInNotice: $($extraInNotice.Count) packages"
|
||||
Write-Host ""
|
||||
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ public sealed partial class ContentFormControl : UserControl
|
||||
|
||||
// LOAD-BEARING: if you don't hang onto a reference to the RenderedAdaptiveCard
|
||||
// then the GC might clean it up sometime, even while the card is in the UI
|
||||
// tree. If this gets GC'ed, then it'll revoke our Action handler, and the
|
||||
// tree. If this gets GC'd, then it'll revoke our Action handler, and the
|
||||
// form will do seemingly nothing.
|
||||
private RenderedAdaptiveCard? _renderedCard;
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ Projects of interest are:
|
||||
|
||||
|
||||
[Initial SDK Spec]: ./doc/initial-sdk-spec/initial-sdk-spec.md
|
||||
[generic samples]: ./ext/SamplePagesExtension
|
||||
[real samples]: ./ext/ProcessMonitorExtension
|
||||
[generic samples]: ./Exts/SamplePagesExtension
|
||||
[real samples]: ./Exts/ProcessMonitorExtension
|
||||
[real extensions that we've "shipped" already]: https://github.com/zadjii/CmdPalExtensions/blob/main/src/extensions
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
@@ -23,10 +23,6 @@ namespace RegistryPreviewUILib
|
||||
{
|
||||
private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
|
||||
// Indicator if we loaded/reloaded/saved a file and need to skip TextChanged event one time.
|
||||
// (Solves the problem that enabling the event handler fires it one time.)
|
||||
private static bool editorContentChangedScripted;
|
||||
|
||||
/// <summary>
|
||||
/// Event that is will prevent the app from closing if the "save file" flag is active
|
||||
/// </summary>
|
||||
@@ -81,67 +77,6 @@ namespace RegistryPreviewUILib
|
||||
MonacoEditor.Focus(FocusState.Programmatic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// New button action: Ask to save last changes and reset editor content to reg header only
|
||||
/// </summary>
|
||||
private async void NewButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Check to see if the current file has been saved
|
||||
if (saveButton.IsEnabled)
|
||||
{
|
||||
ContentDialog contentDialog = new ContentDialog()
|
||||
{
|
||||
Title = resourceLoader.GetString("YesNoCancelDialogTitle"),
|
||||
Content = resourceLoader.GetString("YesNoCancelDialogContent"),
|
||||
PrimaryButtonText = resourceLoader.GetString("YesNoCancelDialogPrimaryButtonText"),
|
||||
SecondaryButtonText = resourceLoader.GetString("YesNoCancelDialogSecondaryButtonText"),
|
||||
CloseButtonText = resourceLoader.GetString("YesNoCancelDialogCloseButtonText"),
|
||||
DefaultButton = ContentDialogButton.Primary,
|
||||
};
|
||||
|
||||
// Use this code to associate the dialog to the appropriate AppWindow by setting
|
||||
// the dialog's XamlRoot to the same XamlRoot as an element that is already present in the AppWindow.
|
||||
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
|
||||
{
|
||||
contentDialog.XamlRoot = this.Content.XamlRoot;
|
||||
}
|
||||
|
||||
ContentDialogResult contentDialogResult = await contentDialog.ShowAsync();
|
||||
switch (contentDialogResult)
|
||||
{
|
||||
case ContentDialogResult.Primary:
|
||||
// Save, then continue the new action
|
||||
if (!AskFileName(string.Empty) ||
|
||||
!SaveFile())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
case ContentDialogResult.Secondary:
|
||||
// Don't save and continue the new action!
|
||||
break;
|
||||
default:
|
||||
// Don't open the new action!
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// mute the TextChanged handler to make for clean UI
|
||||
MonacoEditor.TextChanged -= MonacoEditor_TextChanged;
|
||||
|
||||
// reset editor, file info and ui.
|
||||
_appFileName = string.Empty;
|
||||
ResetEditorAndFile();
|
||||
|
||||
// disable buttons that do not make sense
|
||||
UpdateUnsavedFileState(false);
|
||||
refreshButton.IsEnabled = false;
|
||||
|
||||
// restore the TextChanged handler
|
||||
ButtonAction_RestoreTextChangedEvent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses a picker to select a new file to open
|
||||
/// </summary>
|
||||
@@ -172,15 +107,11 @@ namespace RegistryPreviewUILib
|
||||
{
|
||||
case ContentDialogResult.Primary:
|
||||
// Save, then continue the file open
|
||||
if (!AskFileName(string.Empty) ||
|
||||
!SaveFile())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SaveFile();
|
||||
break;
|
||||
case ContentDialogResult.Secondary:
|
||||
// Don't save and continue the file open!
|
||||
saveButton.IsEnabled = false;
|
||||
break;
|
||||
default:
|
||||
// Don't open the new file!
|
||||
@@ -207,16 +138,14 @@ namespace RegistryPreviewUILib
|
||||
{
|
||||
// mute the TextChanged handler to make for clean UI
|
||||
MonacoEditor.TextChanged -= MonacoEditor_TextChanged;
|
||||
|
||||
// update file name
|
||||
_appFileName = storageFile.Path;
|
||||
UpdateToolBarAndUI(await OpenRegistryFile(_appFileName));
|
||||
|
||||
// disable the Save button as it's a new file
|
||||
UpdateUnsavedFileState(false);
|
||||
saveButton.IsEnabled = false;
|
||||
|
||||
// Restore the event handler as we're loaded
|
||||
ButtonAction_RestoreTextChangedEvent();
|
||||
MonacoEditor.TextChanged += MonacoEditor_TextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,14 +154,7 @@ namespace RegistryPreviewUILib
|
||||
/// </summary>
|
||||
private void SaveButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!AskFileName(string.Empty))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// save and update window title
|
||||
// error handling and ui update happens in SaveFile() method
|
||||
_ = SaveFile();
|
||||
SaveFile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -240,24 +162,47 @@ namespace RegistryPreviewUILib
|
||||
/// </summary>
|
||||
private async void SaveAsButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// mute the TextChanged handler to make for clean UI
|
||||
MonacoEditor.TextChanged -= MonacoEditor_TextChanged;
|
||||
// Save out a new REG file and then open it - we have to use the direct Win32 method because FileOpenPicker crashes when it's
|
||||
// called while running as admin
|
||||
IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(_mainWindow);
|
||||
string filename = SaveFilePicker.ShowDialog(
|
||||
windowHandle,
|
||||
resourceLoader.GetString("SuggestFileName"),
|
||||
resourceLoader.GetString("FilterRegistryName") + '\0' + "*.reg" + '\0' + resourceLoader.GetString("FilterAllFiles") + '\0' + "*.*" + '\0' + '\0',
|
||||
resourceLoader.GetString("SaveDialogTitle"));
|
||||
|
||||
if (!AskFileName(_appFileName) || !SaveFile())
|
||||
if (filename == string.Empty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_appFileName = filename;
|
||||
SaveFile();
|
||||
UpdateToolBarAndUI(await OpenRegistryFile(_appFileName));
|
||||
|
||||
// restore the TextChanged handler
|
||||
ButtonAction_RestoreTextChangedEvent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads the current REG file from storage
|
||||
/// </summary>
|
||||
private async void RefreshButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// mute the TextChanged handler to make for clean UI
|
||||
MonacoEditor.TextChanged -= MonacoEditor_TextChanged;
|
||||
|
||||
// reload the current Registry file and update the toolbar accordingly.
|
||||
UpdateToolBarAndUI(await OpenRegistryFile(_appFileName), true, true);
|
||||
|
||||
// disable the Save button as it's a new file
|
||||
saveButton.IsEnabled = false;
|
||||
|
||||
// restore the TextChanged handler
|
||||
MonacoEditor.TextChanged += MonacoEditor_TextChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the editor content
|
||||
/// </summary>
|
||||
private async void NewButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Check to see if the current file has been saved
|
||||
if (saveButton.IsEnabled)
|
||||
@@ -265,9 +210,10 @@ namespace RegistryPreviewUILib
|
||||
ContentDialog contentDialog = new ContentDialog()
|
||||
{
|
||||
Title = resourceLoader.GetString("YesNoCancelDialogTitle"),
|
||||
Content = resourceLoader.GetString("ReloadDialogContent"),
|
||||
PrimaryButtonText = resourceLoader.GetString("ReloadDialogPrimaryButtonText"),
|
||||
CloseButtonText = resourceLoader.GetString("ReloadDialogCloseButtonText"),
|
||||
Content = resourceLoader.GetString("YesNoCancelDialogContent"),
|
||||
PrimaryButtonText = resourceLoader.GetString("YesNoCancelDialogPrimaryButtonText"),
|
||||
SecondaryButtonText = resourceLoader.GetString("YesNoCancelDialogSecondaryButtonText"),
|
||||
CloseButtonText = resourceLoader.GetString("YesNoCancelDialogCloseButtonText"),
|
||||
DefaultButton = ContentDialogButton.Primary,
|
||||
};
|
||||
|
||||
@@ -282,10 +228,15 @@ namespace RegistryPreviewUILib
|
||||
switch (contentDialogResult)
|
||||
{
|
||||
case ContentDialogResult.Primary:
|
||||
// Don't save and continue the reload action!
|
||||
// Save, then continue the file open
|
||||
SaveFile();
|
||||
break;
|
||||
case ContentDialogResult.Secondary:
|
||||
// Don't save and continue the file open!
|
||||
saveButton.IsEnabled = false;
|
||||
break;
|
||||
default:
|
||||
// Don't continue the reload action!
|
||||
// Don't open the new file!
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -293,14 +244,16 @@ namespace RegistryPreviewUILib
|
||||
// mute the TextChanged handler to make for clean UI
|
||||
MonacoEditor.TextChanged -= MonacoEditor_TextChanged;
|
||||
|
||||
// reload the current Registry file and update the toolbar accordingly.
|
||||
UpdateToolBarAndUI(await OpenRegistryFile(_appFileName), true, true);
|
||||
|
||||
// disable the Save button as it's a new file
|
||||
UpdateUnsavedFileState(false);
|
||||
// reset editor, file info and ui.
|
||||
_appFileName = string.Empty;
|
||||
ResetEditorAndFile();
|
||||
|
||||
// restore the TextChanged handler
|
||||
ButtonAction_RestoreTextChangedEvent();
|
||||
MonacoEditor.TextChanged += MonacoEditor_TextChanged;
|
||||
|
||||
// disable buttons that do not make sense
|
||||
saveButton.IsEnabled = false;
|
||||
refreshButton.IsEnabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -361,20 +314,15 @@ namespace RegistryPreviewUILib
|
||||
switch (contentDialogResult)
|
||||
{
|
||||
case ContentDialogResult.Primary:
|
||||
// Save, then continue the merge action
|
||||
if (!AskFileName(string.Empty) ||
|
||||
!SaveFile())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Save, then continue the file open
|
||||
SaveFile();
|
||||
break;
|
||||
case ContentDialogResult.Secondary:
|
||||
// Don't save and continue the merge action!
|
||||
UpdateUnsavedFileState(false);
|
||||
// Don't save and continue the file open!
|
||||
saveButton.IsEnabled = false;
|
||||
break;
|
||||
default:
|
||||
// Don't merge the file!
|
||||
// Don't open the new file!
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -464,27 +412,8 @@ namespace RegistryPreviewUILib
|
||||
_dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
RefreshRegistryFile();
|
||||
if (!editorContentChangedScripted)
|
||||
{
|
||||
UpdateUnsavedFileState(true);
|
||||
}
|
||||
|
||||
editorContentChangedScripted = false;
|
||||
saveButton.IsEnabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets indicator for programatic text change and adds text changed handler
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use this always, if button actions temporary disable the text changed event
|
||||
/// </remarks>
|
||||
private void ButtonAction_RestoreTextChangedEvent()
|
||||
{
|
||||
// Solves the problem that enabling the event handler fires it one time.
|
||||
// These one time fired event would causes wrong unsaved changes state.
|
||||
editorContentChangedScripted = true;
|
||||
MonacoEditor.TextChanged += MonacoEditor_TextChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.UI.Input;
|
||||
@@ -23,9 +22,6 @@ namespace RegistryPreviewUILib
|
||||
{
|
||||
public sealed partial class RegistryPreviewMainPage : Page
|
||||
{
|
||||
private static readonly string _unsavedFileIndicator = "* ";
|
||||
private static readonly char[] _unsavedFileIndicatorChars = [' ', '*'];
|
||||
|
||||
private const string NEWFILEHEADER = "Windows Registry Editor Version 5.00\r\n\r\n";
|
||||
|
||||
private static SemaphoreSlim _dialogSemaphore = new(1);
|
||||
@@ -835,66 +831,42 @@ namespace RegistryPreviewUILib
|
||||
/// </summary>
|
||||
private async void HandleDirtyClosing(string title, string content, string primaryButtonText, string secondaryButtonText, string closeButtonText)
|
||||
{
|
||||
if (_dialogSemaphore.CurrentCount == 0)
|
||||
ContentDialog contentDialog = new ContentDialog()
|
||||
{
|
||||
return;
|
||||
Title = title,
|
||||
Content = content,
|
||||
PrimaryButtonText = primaryButtonText,
|
||||
SecondaryButtonText = secondaryButtonText,
|
||||
CloseButtonText = closeButtonText,
|
||||
DefaultButton = ContentDialogButton.Primary,
|
||||
};
|
||||
|
||||
// Use this code to associate the dialog to the appropriate AppWindow by setting
|
||||
// the dialog's XamlRoot to the same XamlRoot as an element that is already present in the AppWindow.
|
||||
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
|
||||
{
|
||||
contentDialog.XamlRoot = this.Content.XamlRoot;
|
||||
}
|
||||
|
||||
try
|
||||
ContentDialogResult contentDialogResult = await contentDialog.ShowAsync();
|
||||
|
||||
switch (contentDialogResult)
|
||||
{
|
||||
await _dialogSemaphore.WaitAsync();
|
||||
|
||||
ContentDialog contentDialog = new ContentDialog()
|
||||
{
|
||||
Title = title,
|
||||
Content = content,
|
||||
PrimaryButtonText = primaryButtonText,
|
||||
SecondaryButtonText = secondaryButtonText,
|
||||
CloseButtonText = closeButtonText,
|
||||
DefaultButton = ContentDialogButton.Primary,
|
||||
};
|
||||
|
||||
// Use this code to associate the dialog to the appropriate AppWindow by setting
|
||||
// the dialog's XamlRoot to the same XamlRoot as an element that is already present in the AppWindow.
|
||||
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
|
||||
{
|
||||
contentDialog.XamlRoot = this.Content.XamlRoot;
|
||||
}
|
||||
|
||||
ContentDialogResult contentDialogResult = await contentDialog.ShowAsync();
|
||||
|
||||
switch (contentDialogResult)
|
||||
{
|
||||
case ContentDialogResult.Primary:
|
||||
// Save, then close
|
||||
if (!AskFileName(string.Empty) ||
|
||||
!SaveFile())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
case ContentDialogResult.Secondary:
|
||||
// Don't save, and then close!
|
||||
UpdateUnsavedFileState(false);
|
||||
break;
|
||||
default:
|
||||
// Cancel closing!
|
||||
return;
|
||||
}
|
||||
|
||||
// if we got here, we should try to close again
|
||||
Application.Current.Exit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Normally nothing to catch here.
|
||||
// But for safety the try-catch ensures that we always release the content dialog lock and exit correctly.
|
||||
}
|
||||
finally
|
||||
{
|
||||
_dialogSemaphore.Release();
|
||||
case ContentDialogResult.Primary:
|
||||
// Save, then close
|
||||
SaveFile();
|
||||
break;
|
||||
case ContentDialogResult.Secondary:
|
||||
// Don't save, and then close!
|
||||
saveButton.IsEnabled = false;
|
||||
break;
|
||||
default:
|
||||
// Cancel closing!
|
||||
return;
|
||||
}
|
||||
|
||||
// if we got here, we should try to close again
|
||||
Application.Current.Exit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -954,71 +926,11 @@ namespace RegistryPreviewUILib
|
||||
type.InvokeMember("ProtectedCursor", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance, null, uiElement, new object[] { cursor }, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public void UpdateUnsavedFileState(bool unsavedChanges)
|
||||
{
|
||||
// get, cut and analyze the current title
|
||||
string currentTitle = Regex.Replace(_mainWindow.Title, APPNAME + @"$|\s-\s" + APPNAME + @"$", string.Empty);
|
||||
bool titleContainsIndicator = currentTitle.StartsWith(_unsavedFileIndicator, StringComparison.CurrentCultureIgnoreCase);
|
||||
|
||||
// update window title and save button state
|
||||
if (unsavedChanges)
|
||||
{
|
||||
saveButton.IsEnabled = true;
|
||||
|
||||
if (!titleContainsIndicator)
|
||||
{
|
||||
_updateWindowTitleFunction(_unsavedFileIndicator + currentTitle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
saveButton.IsEnabled = false;
|
||||
|
||||
if (titleContainsIndicator)
|
||||
{
|
||||
_updateWindowTitleFunction(currentTitle.TrimStart(_unsavedFileIndicatorChars));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ask the user for the file path if it is unknown because of an unsaved file
|
||||
/// </summary>
|
||||
/// <param name="fileName">If not empty always ask for a file path and use the value as name.</param>
|
||||
/// <returns>Returns true if user selected a path, otherwise false</returns>
|
||||
public bool AskFileName(string fileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_appFileName) || !string.IsNullOrEmpty(fileName) )
|
||||
{
|
||||
string fName = string.IsNullOrEmpty(fileName) ? resourceLoader.GetString("SuggestFileName") : fileName;
|
||||
|
||||
// Save out a new REG file and then open it - we have to use the direct Win32 method because FileOpenPicker crashes when it's
|
||||
// called while running as admin
|
||||
IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(_mainWindow);
|
||||
string filename = SaveFilePicker.ShowDialog(
|
||||
windowHandle,
|
||||
fName,
|
||||
resourceLoader.GetString("FilterRegistryName") + '\0' + "*.reg" + '\0' + resourceLoader.GetString("FilterAllFiles") + '\0' + "*.*" + '\0' + '\0',
|
||||
resourceLoader.GetString("SaveDialogTitle"));
|
||||
|
||||
if (filename == string.Empty)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_appFileName = filename;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper method that saves the current file in place, using the current text in editor.
|
||||
/// </summary>
|
||||
private bool SaveFile()
|
||||
private void SaveFile()
|
||||
{
|
||||
bool saveSuccess = true;
|
||||
|
||||
ChangeCursor(gridPreview, true);
|
||||
|
||||
// set up the FileStream for all writing
|
||||
@@ -1042,13 +954,10 @@ namespace RegistryPreviewUILib
|
||||
streamWriter.Close();
|
||||
|
||||
// only change when the save is successful
|
||||
UpdateUnsavedFileState(false);
|
||||
_updateWindowTitleFunction(_appFileName);
|
||||
saveButton.IsEnabled = false;
|
||||
}
|
||||
catch (UnauthorizedAccessException ex)
|
||||
{
|
||||
saveSuccess = false;
|
||||
|
||||
// this exception is thrown if the file is there but marked as read only
|
||||
ShowMessageBox(
|
||||
resourceLoader.GetString("ErrorDialogTitle"),
|
||||
@@ -1057,8 +966,6 @@ namespace RegistryPreviewUILib
|
||||
}
|
||||
catch
|
||||
{
|
||||
saveSuccess = false;
|
||||
|
||||
// this catch handles all other exceptions thrown when trying to write the file out
|
||||
ShowMessageBox(
|
||||
resourceLoader.GetString("ErrorDialogTitle"),
|
||||
@@ -1076,8 +983,6 @@ namespace RegistryPreviewUILib
|
||||
|
||||
// restore the cursor
|
||||
ChangeCursor(gridPreview, false);
|
||||
|
||||
return saveSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1193,4 +1098,4 @@ namespace RegistryPreviewUILib
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@@ -258,18 +258,12 @@
|
||||
<data name="YesNoCancelDialogCloseButtonText" xml:space="preserve">
|
||||
<value>Cancel</value>
|
||||
</data>
|
||||
<data name="ReloadDialogCloseButtonText" xml:space="preserve">
|
||||
<value>No</value>
|
||||
</data>
|
||||
<data name="YesNoCancelDialogContent" xml:space="preserve">
|
||||
<value>Save changes?</value>
|
||||
</data>
|
||||
<data name="YesNoCancelDialogPrimaryButtonText" xml:space="preserve">
|
||||
<value>Save</value>
|
||||
</data>
|
||||
<data name="ReloadDialogPrimaryButtonText" xml:space="preserve">
|
||||
<value>Yes</value>
|
||||
</data>
|
||||
<data name="YesNoCancelDialogSecondaryButtonText" xml:space="preserve">
|
||||
<value>Don't save</value>
|
||||
</data>
|
||||
@@ -306,7 +300,4 @@
|
||||
<data name="NewButton.Label" xml:space="preserve">
|
||||
<value>New</value>
|
||||
</data>
|
||||
<data name="ReloadDialogContent" xml:space="preserve">
|
||||
<value>You lose any unsaved changes. Reload anyway?</value>
|
||||
</data>
|
||||
</root>
|
||||
Reference in New Issue
Block a user