2025-11-24 10:59:56 +08:00
|
|
|
|
using System;
|
2025-11-24 15:44:37 +08:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
2025-11-24 15:45:15 +08:00
|
|
|
|
using System.Text;
|
2025-11-24 10:59:56 +08:00
|
|
|
|
using System.Drawing;
|
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
|
|
|
|
|
|
namespace SlideCombine
|
|
|
|
|
|
{
|
|
|
|
|
|
public partial class Form1 : Form
|
|
|
|
|
|
{
|
|
|
|
|
|
public Form1()
|
|
|
|
|
|
{
|
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
|
|
|
|
|
|
// 设置窗体图标 - 使用嵌入资源
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var stream = GetType().Assembly.GetManifestResourceStream("SlideCombine.app.ico");
|
|
|
|
|
|
if (stream != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.Icon = new Icon(stream);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果图标加载失败,使用默认图标
|
|
|
|
|
|
// this.Icon = SystemIcons.Application;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void btnBrowseSource_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (FolderBrowserDialog dialog = new FolderBrowserDialog())
|
|
|
|
|
|
{
|
2025-11-24 16:07:29 +08:00
|
|
|
|
dialog.Description = "请选择包含PDF文件夹的路径";
|
2025-11-24 10:59:56 +08:00
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
txtSourcePath.Text = dialog.SelectedPath;
|
2025-11-24 16:07:29 +08:00
|
|
|
|
LogInfo($"已选择PDF路径: {dialog.SelectedPath}");
|
2025-11-24 10:59:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 16:14:05 +08:00
|
|
|
|
private void btnBrowseText_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (FolderBrowserDialog dialog = new FolderBrowserDialog())
|
|
|
|
|
|
{
|
|
|
|
|
|
dialog.Description = "请选择包含元数据TXT文件的路径";
|
|
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
txtTextPath.Text = dialog.SelectedPath;
|
|
|
|
|
|
LogInfo($"已选择TXT源路径: {dialog.SelectedPath}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 10:59:56 +08:00
|
|
|
|
private void btnBrowseOutput_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (FolderBrowserDialog dialog = new FolderBrowserDialog())
|
|
|
|
|
|
{
|
2025-11-24 16:14:05 +08:00
|
|
|
|
dialog.Description = "请选择合并后TXT文件的输出路径";
|
2025-11-24 10:59:56 +08:00
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
txtOutputPath.Text = dialog.SelectedPath;
|
2025-11-24 16:14:05 +08:00
|
|
|
|
LogInfo($"已选择最终输出路径: {dialog.SelectedPath}");
|
2025-11-24 10:59:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void btnClear_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
txtSourcePath.Clear();
|
2025-11-24 16:14:05 +08:00
|
|
|
|
txtTextPath.Clear();
|
2025-11-24 10:59:56 +08:00
|
|
|
|
txtOutputPath.Clear();
|
|
|
|
|
|
txtLog.Clear();
|
|
|
|
|
|
progressBar.Value = 0;
|
2025-11-24 16:07:29 +08:00
|
|
|
|
LogInfo("界面已清空");
|
2025-11-24 10:59:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void btnExit_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
2025-11-24 16:07:29 +08:00
|
|
|
|
LogInfo("程序即将退出");
|
2025-11-24 10:59:56 +08:00
|
|
|
|
Application.Exit();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void btnMerge_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
2025-11-24 15:44:37 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 验证输入
|
2025-11-24 16:14:05 +08:00
|
|
|
|
if (string.IsNullOrWhiteSpace(txtSourcePath.Text) ||
|
|
|
|
|
|
string.IsNullOrWhiteSpace(txtTextPath.Text) ||
|
|
|
|
|
|
string.IsNullOrWhiteSpace(txtOutputPath.Text))
|
2025-11-24 15:44:37 +08:00
|
|
|
|
{
|
2025-11-24 16:14:05 +08:00
|
|
|
|
MessageBox.Show("请选择所有三个路径:PDF路径、TXT源路径和输出路径", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
2025-11-24 15:44:37 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!Directory.Exists(txtSourcePath.Text))
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("指定的PDF文件夹路径不存在", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 16:14:05 +08:00
|
|
|
|
if (!Directory.Exists(txtTextPath.Text))
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("指定的TXT源文件路径不存在", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 15:44:37 +08:00
|
|
|
|
// 禁用按钮,防止重复点击
|
|
|
|
|
|
btnMerge.Enabled = false;
|
|
|
|
|
|
btnClear.Enabled = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 重置进度条和日志
|
|
|
|
|
|
progressBar.Value = 0;
|
|
|
|
|
|
txtLog.Clear();
|
|
|
|
|
|
Log("开始处理PDF书签文件...");
|
|
|
|
|
|
|
|
|
|
|
|
// 处理文件
|
2025-11-24 16:14:05 +08:00
|
|
|
|
var results = FileMerger.ProcessAllFolders(txtSourcePath.Text, txtTextPath.Text, txtOutputPath.Text);
|
2025-11-24 15:44:37 +08:00
|
|
|
|
|
|
|
|
|
|
// 显示进度
|
|
|
|
|
|
progressBar.Value = 50;
|
|
|
|
|
|
Log($"找到 {results.Count} 个文件组需要处理");
|
|
|
|
|
|
|
|
|
|
|
|
// 保存结果
|
|
|
|
|
|
FileMerger.SaveResults(results, txtOutputPath.Text);
|
|
|
|
|
|
|
|
|
|
|
|
progressBar.Value = 100;
|
|
|
|
|
|
|
|
|
|
|
|
// 统计成功和失败的数量
|
|
|
|
|
|
int successCount = 0;
|
|
|
|
|
|
int failCount = 0;
|
|
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var result in results)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (result.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
successCount++;
|
|
|
|
|
|
Log($"✓ 成功处理: {result.BaseFileName} (合并了 {result.SourceFiles.Count} 个文件)");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
failCount++;
|
|
|
|
|
|
Log($"✗ 处理失败: {result.ErrorMessage}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Log($"处理完成! 成功: {successCount}, 失败: {failCount}");
|
|
|
|
|
|
|
|
|
|
|
|
if (successCount > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"书签合并完成!\n成功处理 {successCount} 个文件\n输出路径: {txtOutputPath.Text}",
|
|
|
|
|
|
"处理完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("没有成功处理任何文件,请检查输入路径和文件格式。",
|
|
|
|
|
|
"处理失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Log($"错误: {ex.Message}");
|
|
|
|
|
|
MessageBox.Show($"处理过程中发生错误:\n{ex.Message}",
|
|
|
|
|
|
"错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
// 重新启用按钮
|
|
|
|
|
|
btnMerge.Enabled = true;
|
|
|
|
|
|
btnClear.Enabled = true;
|
|
|
|
|
|
}
|
2025-11-24 10:59:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Log(string msg)
|
|
|
|
|
|
{
|
2025-11-24 16:07:29 +08:00
|
|
|
|
string timestamp = DateTime.Now.ToString("HH:mm:ss");
|
|
|
|
|
|
txtLog.AppendText($"[{timestamp}] {msg}\r\n");
|
|
|
|
|
|
txtLog.ScrollToCaret();
|
|
|
|
|
|
Application.DoEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void LogSuccess(string msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
string timestamp = DateTime.Now.ToString("HH:mm:ss");
|
|
|
|
|
|
txtLog.SelectionStart = txtLog.TextLength;
|
|
|
|
|
|
txtLog.SelectionColor = Color.Green;
|
|
|
|
|
|
txtLog.AppendText($"[{timestamp}] ✅ {msg}\r\n");
|
|
|
|
|
|
txtLog.SelectionColor = txtLog.ForeColor;
|
|
|
|
|
|
txtLog.ScrollToCaret();
|
|
|
|
|
|
Application.DoEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void LogError(string msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
string timestamp = DateTime.Now.ToString("HH:mm:ss");
|
|
|
|
|
|
txtLog.SelectionStart = txtLog.TextLength;
|
|
|
|
|
|
txtLog.SelectionColor = Color.Red;
|
|
|
|
|
|
txtLog.AppendText($"[{timestamp}] ❌ {msg}\r\n");
|
|
|
|
|
|
txtLog.SelectionColor = txtLog.ForeColor;
|
|
|
|
|
|
txtLog.ScrollToCaret();
|
|
|
|
|
|
Application.DoEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void LogInfo(string msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
string timestamp = DateTime.Now.ToString("HH:mm:ss");
|
|
|
|
|
|
txtLog.SelectionStart = txtLog.TextLength;
|
|
|
|
|
|
txtLog.SelectionColor = Color.Blue;
|
|
|
|
|
|
txtLog.AppendText($"[{timestamp}] ℹ️ {msg}\r\n");
|
|
|
|
|
|
txtLog.SelectionColor = txtLog.ForeColor;
|
2025-11-24 10:59:56 +08:00
|
|
|
|
txtLog.ScrollToCaret();
|
|
|
|
|
|
Application.DoEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|