using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using PDFPatcher.Common; using PDFPatcher.Functions; namespace PDFPatcher; public partial class MainForm : Form { static readonly Dictionary __FunctionControls = []; ReportControl _LogControl; #region 公共功能 BackgroundWorker _Worker; readonly FormState _formState = new FormState(); ///获取或指定全屏显示的值。 [Browsable(false)] public bool FullScreen { get; set { if (value == field) { return; } field = value; if (value) { _MainMenu.Visible = _GeneralToolbar.Visible = false; _formState.Maximize(this); } else { _MainMenu.Visible = true; _GeneralToolbar.Visible = AppContext.Toolbar.ShowGeneralToolbar; _formState.Restore(this); } } } /// /// 获取或设置状态栏文本。 /// internal string StatusText { get => _MainStatusLabel.Text; set => _MainStatusLabel.Text = value; } internal event EventHandler> FunctionControlChanged; #region Worker ///获取或指定后台进程。 internal BackgroundWorker GetWorker() { if (_Worker == null) { _Worker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true }; _Worker.DoWork += Worker_DoWork; _Worker.ProgressChanged += Worker_ProgressChanged; _Worker.RunWorkerCompleted += Worker_RunWorkerCompleted; Tracker.SetWorker(_Worker); } return _Worker; } internal bool IsWorkerBusy => _Worker?.IsBusy == true; void Worker_DoWork(object sender, DoWorkEventArgs e) { _Worker.ReportProgress(0); FileHelper.ResetOverwriteMode(); AppContext.Abort = false; } void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { _MainMenu.Enabled = _GeneralToolbar.Enabled = _FunctionContainer.Enabled = true; foreach (TabPage item in _FunctionContainer.TabPages) { item.Enabled = true; } if (e.Error == null || !e.Cancelled) { _LogControl.Complete(); } } public void ResetWorker() { if (_Worker != null) { if (_Worker.IsBusy) { throw new InvalidOperationException("Worker is busy. Can't be reset."); } _Worker.Dispose(); _Worker = null; } } void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { var s = e.UserState as string; if (s == "INC") { _LogControl.IncrementProgress(e.ProgressPercentage); return; } else if (s == "GOAL") { _LogControl.SetGoal(e.ProgressPercentage); return; } else if (s == "TINC") { _LogControl.IncrementTotalProgress(); } else if (s == "TGOAL") { _LogControl.SetTotalGoal(e.ProgressPercentage); } if (e.ProgressPercentage > 0) { _LogControl.SetProgress(e.ProgressPercentage); } else if (e.ProgressPercentage == 0) { _MainMenu.Enabled = _GeneralToolbar.Enabled = _FunctionContainer.Enabled = false; foreach (TabPage item in _FunctionContainer.TabPages) { item.Enabled = false; } _LogControl.Reset(); ShowLogControl(); } else if (s != null) { _LogControl.PrintMessage(s, (Tracker.Category)e.ProgressPercentage); } } #endregion /// /// 设置控件的提示信息。 /// internal void SetTooltip(Control control, string text) { _ToolTip.SetToolTip(control, text); } internal FunctionControl GetFunctionControl(Function functionName) { if (__FunctionControls.TryGetValue(functionName, out FunctionControl f) && !f.IsDisposed) { return f; } switch (functionName) { case Function.FrontPage: f = new FrontPageControl(); break; case Function.Patcher: f = new PatcherControl(); break; case Function.Merger: f = new MergerControl(); break; case Function.BookmarkGenerator: f = new AutoBookmarkControl(); break; case Function.InfoExchanger: f = new InfoExchangerControl(); break; case Function.ExtractPages: f = new ExtractPageControl(); break; case Function.ExtractImages: f = new ExtractImageControl(); break; case Function.Editor: var b = new EditorControl(); b.DocumentChanged += OnDocumentChanged; return b; case Function.Ocr: f = new OcrControl(); break; case Function.RenderPages: f = new RenderImageControl(); break; case Function.About: f = new AboutControl(); break; case Function.Inspector: var d = new DocumentInspectorControl(); d.DocumentChanged += OnDocumentChanged; return d; case Function.Rename: f = new RenameControl(); break; default: return null; } return __FunctionControls[functionName] = f; } void OnDocumentChanged(object sender, DocumentChangedEventArgs args) { FilePath p = args.Path; _MainStatusLabel.Text = p.ToString(); if (!p.IsValidPath) { return; } var t = p.FileNameWithoutExtension; if (t.Length > 20) { t = t.Substring(0, 17) + "..."; } if (sender is Control f) { f = f.Parent; if (f == null) { return; } f.Text = t; } } #endregion public MainForm() { InitializeComponent(); this.OnFirstLoad(OnLoad); } protected override void WndProc(ref Message m) { base.WndProc(ref m); if (m.Msg == FormHelper.ProcMsg) { OpenFiles(FormHelper.GetCopyDataContent(ref m).Split('\n')); Activate(); } } protected override void OnFormClosing(FormClosingEventArgs e) { base.OnFormClosing(e); int n = 0; foreach (var item in _FunctionContainer.GetPrimaryControlsInTabs()) { if (item.IsDirty) { n++; } } if (n != 0 && !this.ConfirmYesBox(Messages.ConfirmCloseNDirtyDocument.Replace("", n.ToText()))) { e.Cancel = true; } else if (FullScreen) { FullScreen = false; e.Cancel = true; } } void OnLoad() { Processor.PdfHelper.ToggleReaderDebugMode(true); // 打开容错模式 Processor.PdfHelper.ToggleUnethicalMode(true); // 打开强制读取加密文档模式 bool firstLoad; try { firstLoad = !AppContext.Load(null); } catch (Exception) { // ignore loading exception firstLoad = true; } _MainMenu.ScaleElements(); Text = Constants.AppName + " [" + Application.ProductVersion + "]"; MinimumSize = Size; AllowDrop = true; DragEnter += (s, args) => args.FeedbackDragFileOver(Constants.FileExtensions.Pdf); DragDrop += (s, args) => OpenFiles(args.DropFileOver(Constants.FileExtensions.Pdf)); FormClosed += MainForm_FormClosed; AppContext.WindowStatus.Position(this); SetupCustomizeToolbar(); if (_GeneralToolbar.Visible = AppContext.Toolbar.ShowGeneralToolbar) { ScaleToolbar(); } _OpenPdfDialog.DefaultExt = Constants.FileExtensions.Pdf; _OpenPdfDialog.Filter = Constants.FileExtensions.PdfOrXmlFilter; _LogControl = new ReportControl { Location = _FunctionContainer.Location, Size = _FunctionContainer.Size, Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Right }; Controls.Add(_LogControl); HideLogControl(); _LogControl.VisibleChanged += (s, args) => _FunctionContainer.Visible = !_LogControl.Visible; _OpenConfigDialog.FileName = _SaveConfigDialog.FileName = Constants.AppName + "配置文件" + Constants.FileExtensions.Json; _OpenConfigDialog.Filter = _SaveConfigDialog.Filter = Constants.FileExtensions.JsonFilter; _FunctionContainer.Font = new Font(SystemFonts.CaptionFont.FontFamily.Name, 9); _FunctionContainer.ImageList = new ImageList(); _FunctionContainer.DisplayStyleProvider.SelectedTextStyle = FontStyle.Bold; _FunctionContainer.AllowDrop = true; _FunctionContainer.MiddleClickCloseTab = true; _FunctionContainer.DoubleClickCloseTab = true; _FunctionContainer.TabClosing += (s, args) => { if (_FunctionContainer.SafeCloseTab(args.TabPage)) { _MainStatusLabel.Text = String.Empty; } args.Cancel = true; }; _FunctionContainer.Selected += SelectedFunctionChanged; _FunctionContainer.Deselected += FunctionDeselected; // 关闭启动屏幕窗口 using (var closeSplashEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset, "CloseSplashScreenEvent" + Constants.AppEngName)) { closeSplashEvent.Set(); } SelectFunctionList(Function.FrontPage); _GeneralToolbar.ItemClicked += MenuCommand; if (AppContext.CheckUpdateDate < DateTime.Today) { CheckUpdate(); if (AppContext.CheckUpdateInterval != Int32.MaxValue) { AppContext.CheckUpdateDate = DateTime.Today + TimeSpan.FromDays(AppContext.CheckUpdateInterval); } } var ca = Environment.GetCommandLineArgs(); if (ca.HasContent()) { OpenFiles(ca); } #if DEBUG iTextSharp.text.io.StreamUtil.AddToResourceSearch("iTextAsian.dll"); #endif } void OpenFiles(string[] files) { foreach (var item in files) { var p = new FilePath(item); if (p.ExistsFile && p.HasExtension(Constants.FileExtensions.Pdf)) { OpenFileWithEditor(p.ToFullPath()); } } } void CheckUpdate() { var client = new System.Net.WebClient(); client.DownloadDataCompleted += (s, args) => { if (args.Error != null) { goto Exit; } try { var x = new System.Xml.XmlDocument(); x.Load(new System.IO.MemoryStream(args.Result)); var r = x.DocumentElement; var u = r.GetAttribute("url"); if (!String.IsNullOrEmpty(u) && new Version(ProductVersion) < new Version(r.GetAttribute("version")) && this.ConfirmOKBox("发现新版本,是否前往下载?")) { this.ShowDialog(); } } catch (Exception) { FormHelper.ErrorBox("版本信息文件格式错误,请稍候重试。"); } Exit: client.Dispose(); client = null; }; client.DownloadDataAsync(new Uri(Constants.AppUpdateFile)); } void MenuCommand(object sender, ToolStripItemClickedEventArgs e) { var ci = e.ClickedItem; var t = ci.Tag as string; if (!String.IsNullOrEmpty(t)) { SelectFunctionList((Function)Enum.Parse(typeof(Function), t)); return; } ci.HidePopupMenu(); if (ci.OwnerItem == _RecentFiles) { ((FunctionControl)GetActiveFunctionControl()) .RecentFileItemClicked ?.Invoke(_MainMenu, e); } else { ExecuteCommand(ci.Name); } } internal void ExecuteCommand(string commandName) { if (commandName == Commands.ResetOptions) { if (GetActiveFunctionControl() is IResettableControl f && FormHelper.YesNoBox("是否将当前功能恢复为默认设置?") == DialogResult.Yes) { f.Reset(); } } else if (commandName == Commands.RestoreOptions && _OpenConfigDialog.ShowDialog() == DialogResult.OK) { if (!AppContext.Load(_OpenConfigDialog.FileName)) { FormHelper.ErrorBox("无法加载指定的配置文件。"); return; } foreach (Control item in __FunctionControls.Values) { (item as IResettableControl)?.Reload(); } SetupCustomizeToolbar(); } else if (commandName == Commands.SaveOptions && _SaveConfigDialog.ShowDialog() == DialogResult.OK) { AppContext.Save(_SaveConfigDialog.FileName, false, false); } else if (commandName == Commands.LogWindow) { ShowLogControl(); } else if (commandName == Commands.CreateShortcut) { ShellHelper.CreateShortcut(); } else if (commandName == Commands.VisitHomePage) { ShellHelper.VisitHomePage(); } else if (commandName == Commands.CheckUpdate) { this.ShowDialog(); } else if (commandName == Commands.Close) { if (_FunctionContainer.SelectedTab.Tag.CastOrDefault() == Function.FrontPage) { return; } _FunctionContainer.SelectedTab.Dispose(); } else if (commandName == Commands.CustomizeToolbar || commandName == "_CustomizeToolbarCommand") { this.ShowDialog(); SetupCustomizeToolbar(); } else if (commandName == Commands.ShowGeneralToolbar) { _FunctionContainer.SuspendLayout(); if (_GeneralToolbar.Visible = AppContext.Toolbar.ShowGeneralToolbar = !AppContext.Toolbar.ShowGeneralToolbar) { ScaleToolbar(); } _FunctionContainer.PerformLayout(); } else if (commandName == Commands.Exit) { Close(); } else if (commandName == Commands.FullScreenDisplay) { FullScreen = !FullScreen; } else if (GetActiveFunctionControl() is FunctionControl f) { if (commandName == Commands.Action && f.DefaultButton != null) { f.DefaultButton.PerformClick(); } else { f.ExecuteCommand(commandName); } } } void SetupCustomizeToolbar() { AppContext.Toolbar.RemoveInvalidButtons(); for (int i = _GeneralToolbar.Items.Count - 1; i > 0; i--) { _GeneralToolbar.Items[i].Dispose(); } foreach (var item in AppContext.Toolbar.Buttons) { if (!item.Visible) { continue; } _GeneralToolbar.Items.Add(item.CreateButton()); } } void ScaleToolbar() { _GeneralToolbar.ScaleElements(); } Control GetActiveFunctionControl() { return _FunctionContainer.FirstControlInActiveTab; } internal void OpenFileWithEditor(FilePath path) { path = path.ToFullPath(); EditorControl c; foreach (var editor in GetOpenedDocumentEditors()) { if ((c = editor as EditorControl) != null && path.Equals(c.DocumentPath)) { _FunctionContainer.SelectedTab = (TabPage)c.Parent; _FunctionContainer.Invalidate(); return; } } c = SelectFunctionList(Function.Editor) as EditorControl; if (String.IsNullOrEmpty(path)) { c.ExecuteCommand(Commands.Open); } else { c.ExecuteCommand(Commands.OpenFile, path); } } IEnumerable GetOpenedDocumentEditors() { foreach (TabPage item in _FunctionContainer.TabPages) { if (item.Controls.Count != 0 && item.Controls[0] is IDocumentEditor editor) { yield return editor; } } } internal FunctionControl SelectFunctionList(Function func) { if (func == Function.PatcherOptions) { this.ShowDialog(); } else if (func == Function.MergerOptions) { this.ShowDialog(); } else if (func == Function.InfoFileOptions) { this.ShowDialog(); } else if (func == Function.Options) { this.ShowDialog(); } else { HideLogControl(); var p = (GetActiveFunctionControl() as IDocumentSource)?.DocumentPath; var c = GetFunctionControl(func); foreach (TabPage item in _FunctionContainer.TabPages) { if (item.Controls.Count > 0 && item.Controls[0] == c) { _FunctionContainer.SelectedTab = item; if (!String.IsNullOrEmpty(p) && c is IDocumentSource tc && String.IsNullOrEmpty(tc.DocumentPath)) { c.ExecuteCommand(Commands.OpenFile, p); } return c; } } var t = new TabPage(c.FunctionName) { Font = SystemFonts.SmallCaptionFont }; var im = _FunctionContainer.ImageList.Images; for (int i = im.Count - 1; i >= 0; i--) { if (im[i] == c.IconImage) { t.ImageIndex = i; break; } } if (t.ImageIndex < 0) { im.Add(c.IconImage); t.ImageIndex = im.Count - 1; } t.Tag = func; _FunctionContainer.TabPages.Add(t); c.Size = t.ClientSize; c.Dock = DockStyle.Fill; t.Controls.Add(c); _FunctionContainer.SelectedTab = t; if (func != Function.Editor && !String.IsNullOrEmpty(p)) { c.ExecuteCommand(Commands.OpenFile, p); } AcceptButton = c.DefaultButton; return c; } return null; } void FunctionDeselected(object sender, TabControlEventArgs args) { if (GetActiveFunctionControl() is FunctionControl c) { c.OnDeselected(); } } void SelectedFunctionChanged(object sender, TabControlEventArgs args) { if (GetActiveFunctionControl() is FunctionControl c) { c.OnSelected(); _MainStatusLabel.Text = c is IDocumentEditor b ? b.DocumentPath : Messages.Welcome; AcceptButton = c.DefaultButton; FunctionControlChanged?.Invoke(this, new EventArgs(c)); } } internal string ShowPdfFileDialog() { return _OpenPdfDialog.ShowDialog() == DialogResult.OK ? _OpenPdfDialog.FileName : null; } void MainForm_FormClosed(object sender, FormClosedEventArgs e) { AppContext.Save(null, true, true); } void HideLogControl() { _LogControl.Hide(); } void ShowLogControl() { _LogControl.Show(); } void MenuOpening(object sender, EventArgs e) { if (GetActiveFunctionControl() is FunctionControl f) { f.SetupMenu(sender as ToolStripMenuItem); } } void RecentFileMenuOpening(object sender, EventArgs e) { if (GetActiveFunctionControl() is FunctionControl f && f.ListRecentFiles != null) { f.ListRecentFiles(sender, e); } } }