mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-11 17:59:17 +00:00
QL will display a UI prompting for a password. Upon entering the correct password, the PDF file will be reopened.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
<UserControl x:Class="QuickLook.Plugin.PDFViewer.PasswordControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:QuickLook.Plugin.PDFViewer"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<Grid>
|
||||
<Border HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Background="{DynamicResource CardBackground}"
|
||||
BorderBrush="{DynamicResource CardBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="5">
|
||||
<Grid Margin="24">
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="titleTextBlock"
|
||||
FontSize="18"
|
||||
FontWeight="DemiBold"
|
||||
Text="Enter Password" />
|
||||
<TextBlock x:Name="hintTextBlock"
|
||||
Margin="0,20,0,0"
|
||||
Text="This file is password protected. Please enter the password to open the file." />
|
||||
<PasswordBox x:Name="passwordBox"
|
||||
MinWidth="400"
|
||||
Margin="0,16,0,0" />
|
||||
<TextBlock x:Name="passwordErrorTextBlock"
|
||||
MinWidth="400"
|
||||
Margin="0,16,0,0"
|
||||
Foreground="Red"
|
||||
Text="Check your password"
|
||||
Visibility="Collapsed" />
|
||||
<Grid MinWidth="400" Margin="0,16,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button x:Name="openFileButton"
|
||||
Grid.Column="0"
|
||||
Margin="0,0,4,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Content="Open File" />
|
||||
<Button x:Name="cancelButton"
|
||||
Grid.Column="1"
|
||||
Margin="4,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Content="Cancel" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,74 @@
|
||||
// Copyright © 2024 ema
|
||||
//
|
||||
// This file is part of QuickLook program.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using QuickLook.Common.Helpers;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace QuickLook.Plugin.PDFViewer;
|
||||
|
||||
public partial class PasswordControl : UserControl
|
||||
{
|
||||
public event Func<string, bool> PasswordRequested;
|
||||
|
||||
public bool Result { get; private set; } = false;
|
||||
public string Password => passwordBox.Dispatcher.Invoke(() => passwordBox.Password);
|
||||
|
||||
public PasswordControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
string domain = Assembly.GetExecutingAssembly().GetName().Name;
|
||||
titleTextBlock.Text = TranslationHelper.Get("PW_Title", domain: domain);
|
||||
hintTextBlock.Text = TranslationHelper.Get("Pw_Hint", domain: domain);
|
||||
passwordErrorTextBlock.Text = TranslationHelper.Get("PW_Error", domain: domain);
|
||||
openFileButton.Content = TranslationHelper.Get("BTN_OpenFile", domain: domain);
|
||||
cancelButton.Content = TranslationHelper.Get("BTN_Cancel", domain: domain);
|
||||
openFileButton.Click += OpenFileButton_Click;
|
||||
cancelButton.Click += CancelButton_Click;
|
||||
}
|
||||
|
||||
private void OpenFileButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Password))
|
||||
{
|
||||
Result = true;
|
||||
|
||||
if (PasswordRequested != null)
|
||||
{
|
||||
bool accepted = PasswordRequested.Invoke(Password);
|
||||
|
||||
if (!accepted)
|
||||
{
|
||||
passwordErrorTextBlock.Dispatcher.Invoke(() => passwordErrorTextBlock.Visibility = Visibility.Visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Result = false;
|
||||
|
||||
if (Window.GetWindow(this) is Window window)
|
||||
{
|
||||
window.Close();
|
||||
}
|
||||
}
|
||||
}
|
@@ -23,12 +23,12 @@ namespace QuickLook.Plugin.PDFViewer;
|
||||
|
||||
public class PdfDocumentWrapper : IDisposable
|
||||
{
|
||||
public PdfDocumentWrapper(Stream stream)
|
||||
public PdfDocumentWrapper(Stream stream, string password = null)
|
||||
{
|
||||
PdfStream = new MemoryStream((int)stream.Length);
|
||||
stream.CopyTo(PdfStream);
|
||||
|
||||
PdfDocument = PdfDocument.Load(PdfStream);
|
||||
PdfDocument = PdfDocument.Load(PdfStream, password);
|
||||
}
|
||||
|
||||
public PdfDocument PdfDocument { get; private set; }
|
||||
|
@@ -213,13 +213,13 @@ public partial class PdfViewerControl : UserControl, INotifyPropertyChanged, IDi
|
||||
}
|
||||
}
|
||||
|
||||
public static Size GetDesiredControlSizeByFirstPage(string path)
|
||||
public static Size GetDesiredControlSizeByFirstPage(string path, string password = null)
|
||||
{
|
||||
Size size;
|
||||
|
||||
using (var s = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
using (var tempHandle = PdfDocument.Load(s))
|
||||
using (var tempHandle = PdfDocument.Load(s, password))
|
||||
{
|
||||
size = new Size(0, 0);
|
||||
tempHandle.PageSizes.Take(5).ForEach(p =>
|
||||
@@ -236,10 +236,10 @@ public partial class PdfViewerControl : UserControl, INotifyPropertyChanged, IDi
|
||||
return new Size(size.Width * 3, size.Height * 3);
|
||||
}
|
||||
|
||||
public void LoadPdf(string path)
|
||||
public void LoadPdf(string path, string password = null)
|
||||
{
|
||||
var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
PdfDocumentWrapper = new PdfDocumentWrapper(stream);
|
||||
PdfDocumentWrapper = new PdfDocumentWrapper(stream, password);
|
||||
_pdfLoaded = true;
|
||||
|
||||
if (PdfDocumentWrapper.PdfDocument.PageCount < 2)
|
||||
|
@@ -15,11 +15,13 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using PdfiumViewer;
|
||||
using QuickLook.Common.Plugin;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace QuickLook.Plugin.PDFViewer;
|
||||
@@ -29,6 +31,7 @@ public class Plugin : IViewer
|
||||
private ContextObject _context;
|
||||
private string _path;
|
||||
private PdfViewerControl _pdfControl;
|
||||
private PasswordControl _passwordControl;
|
||||
|
||||
public int Priority => 0;
|
||||
|
||||
@@ -55,9 +58,16 @@ public class Plugin : IViewer
|
||||
_context = context;
|
||||
_path = path;
|
||||
|
||||
var desiredSize = PdfViewerControl.GetDesiredControlSizeByFirstPage(path);
|
||||
|
||||
context.SetPreferredSizeFit(desiredSize, 0.9);
|
||||
try
|
||||
{
|
||||
var desiredSize = PdfViewerControl.GetDesiredControlSizeByFirstPage(path);
|
||||
context.SetPreferredSizeFit(desiredSize, 0.9);
|
||||
}
|
||||
catch (PdfException ex) when (ex.Message == "Password required or incorrect password")
|
||||
{
|
||||
// Fallback to a size to request the password
|
||||
context.PreferredSize = new Size { Width = 800, Height = 600 };
|
||||
}
|
||||
}
|
||||
|
||||
public void View(string path, ContextObject context)
|
||||
@@ -67,7 +77,7 @@ public class Plugin : IViewer
|
||||
|
||||
Exception exception = null;
|
||||
|
||||
_pdfControl.Dispatcher.BeginInvoke(new Action(() =>
|
||||
_ = _pdfControl.Dispatcher.BeginInvoke(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -78,11 +88,46 @@ public class Plugin : IViewer
|
||||
_pdfControl.CurrentPageChanged += UpdateWindowCaption;
|
||||
context.IsBusy = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (PdfException ex) when (ex.Message == "Password required or incorrect password")
|
||||
{
|
||||
exception = e;
|
||||
// Fallback to request a password
|
||||
_passwordControl = new PasswordControl();
|
||||
_passwordControl.PasswordRequested += (string password) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var desiredSize = PdfViewerControl.GetDesiredControlSizeByFirstPage(path, password);
|
||||
context.SetPreferredSizeFit(desiredSize, 0.9); // Actually it is no longer effective here
|
||||
|
||||
context.ViewerContent = _pdfControl;
|
||||
|
||||
context.IsBusy = true;
|
||||
_pdfControl.LoadPdf(path, password);
|
||||
|
||||
context.Title = $"1 / {_pdfControl.TotalPages}: {Path.GetFileName(path)}";
|
||||
|
||||
_pdfControl.CurrentPageChanged += UpdateWindowCaption;
|
||||
context.IsBusy = false;
|
||||
}
|
||||
catch (PdfException ex) when (ex.Message == "Password required or incorrect password")
|
||||
{
|
||||
// This password is not accepted
|
||||
return false;
|
||||
}
|
||||
|
||||
// This password is accepted
|
||||
return true;
|
||||
};
|
||||
|
||||
context.ViewerContent = _passwordControl;
|
||||
context.Title = $"[PASSWORD PROTECTED] {Path.GetFileName(path)}";
|
||||
context.IsBusy = false;
|
||||
}
|
||||
}), DispatcherPriority.Loaded).Wait();
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
}
|
||||
}, DispatcherPriority.Loaded).Wait();
|
||||
|
||||
if (exception != null)
|
||||
ExceptionDispatchInfo.Capture(exception).Throw();
|
||||
|
@@ -86,6 +86,12 @@
|
||||
<Resource Include="Resources\loading.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Translations.config">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\GitVersion.cs">
|
||||
<Link>Properties\GitVersion.cs</Link>
|
||||
|
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Translations>
|
||||
<en>
|
||||
<PW_Title>Enter Password</PW_Title>
|
||||
<Pw_Hint>This file is password protected. Please enter the password to open the file.</Pw_Hint>
|
||||
<PW_Error>Check your password</PW_Error>
|
||||
<BTN_OpenFile>Open File</BTN_OpenFile>
|
||||
<BTN_Cancel>BTN_Cancel</BTN_Cancel>
|
||||
</en>
|
||||
<ja-JP>
|
||||
<PW_Title>パスワード入力</PW_Title>
|
||||
<Pw_Hint>このファイルではパスワードで保護されています。ファイルを開くにはパスワードを入力してください。</Pw_Hint>
|
||||
<PW_Error>パスワードを確認してください</PW_Error>
|
||||
<BTN_OpenFile>ファイルを開く</BTN_OpenFile>
|
||||
<BTN_Cancel>キャンセル</BTN_Cancel>
|
||||
</ja-JP>
|
||||
<zh-CN>
|
||||
<PW_Title>输入密码</PW_Title>
|
||||
<Pw_Hint>此文件受密码保护。请输入密码以打开文件。</Pw_Hint>
|
||||
<PW_Error>检查您的密码</PW_Error>
|
||||
<BTN_OpenFile>打开文件</BTN_OpenFile>
|
||||
<BTN_Cancel>取消</BTN_Cancel>
|
||||
</zh-CN>
|
||||
<zh-TW>
|
||||
<PW_Title>輸入密碼</PW_Title>
|
||||
<Pw_Hint>此檔案受密碼保護。請輸入密碼以開啟檔案。</Pw_Hint>
|
||||
<PW_Error>檢查您的密碼</PW_Error>
|
||||
<BTN_OpenFile>開啟檔案</BTN_OpenFile>
|
||||
<BTN_Cancel>取消</BTN_Cancel>
|
||||
</zh-TW>
|
||||
</Translations>
|
Reference in New Issue
Block a user