diff --git a/example/ppic-assoc/README.md b/example/ppic-assoc/README.md deleted file mode 100644 index b6856cb..0000000 --- a/example/ppic-assoc/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Pineapple Picture Association - -TODO diff --git a/example/qwfassoc/PROMPT.txt b/example/qwfassoc/PROMPT.txt new file mode 100644 index 0000000..24111d2 --- /dev/null +++ b/example/qwfassoc/PROMPT.txt @@ -0,0 +1,232 @@ +我要求你使用Qt Widget编写一个GUI程序。该GUI程序是wfassoc的一个可视化界面。wfassoc是一个由Rust编写,并暴露出C接口,可以操作Windows注册表,来管理应用程序的注册和卸载,以及文件关联的动态链接库。 + +我要求你在@example/qwfassoc/TASKS.md 中先做好详细的规划,而不是上来就写代码。我会安排其他人来负责执行你做的规划。 + +# 项目要求 + +- 使用Qt Widget编写界面,而不是QML。 +- 使用UI文件而不是C++语句来构建界面。 +- 我使用的是Qt 6,使用CMake作为构建系统,不要使用Qt的qmake。 +- 使用toml11作为TOML读取库。 + +# 界面要求 + +这是一个基于 Qt Widgets 的标准对话框界面描述。你可以按照以下层级结构来构建代码: + +## 主窗口容器 (Main Window) + +* 类: `QDialog`。 +* 窗口标题: "xxx选项"。xxx在应用程序初始化时,通过wfassoc的Program提供的接口,运行时获取。 +* 窗口图标:在应用程序初始化时,通过wfassoc的Program提供的接口,运行时获取。 +* 大小限制:固定大小480x600 + +## 选项卡 (Top Tabs) + +* 组件: `QTabWidget`。 +* 标签页 (Tabs): 从左到右依次添加以下标签页: + 1. 应用程序 + 2. 文件关联 +* 大小:选项卡占据对话框全部内容 + +## "应用程序"选项卡内容 + +该选项卡内部使用垂直布局 (`QVBoxLayout`),包含一个主要的分组区域: + +### 区域内容 + +* 容器: `QGroupBox`。 +* 区域标题:安装与卸载 +* 布局: 垂直布局 (`QVBoxLayout`)。 + * 上半部分 + * 水平布局(`QHBoxLayout`)。 + * 左侧: 一个 `QLabel` 显示图标,该图标表示要设定的应用程序的图标。在应用程序初始化时,通过wfassoc的Program提供的接口,运行时获取。 + * 右侧: 一个 `QLabel` 显示文本"在此安装或卸载xxx",表示要设定的应用程序的名称。xxx在应用程序初始化时,通过wfassoc的Program提供的接口,运行时获取。 (文本需要设置自动换行 `setWordWrap(true)`)。 + * 下半部分 + * 水平布局(`QHBoxLayout`)。 + * 内容为两个 `QPushButton`,文本分别为: + * 安装:为当前对象(系统或当前用户,由应用程序初始化时从命令行参数获取)安装应用。如果应用程序已经安装,则不可点击。 + * 卸载:为当前对象(系统或当前用户,由应用程序初始化时从命令行参数获取)卸载应用。如果应用程序没有安装,则不可点击。 + +## "文件关联"选项卡内容 + +在这个选项页内部,使用一个垂直布局 (`QVBoxLayout`) 来排列以下控件: + +* 说明文本: + * 组件: `QLabel`。 + * 文本: "使用 xxx 关联的文件类型:"。xxx在应用程序初始化时,通过wfassoc的Program提供的接口,运行时获取。 + +* 功能按钮行: + * 布局: `QHBoxLayout` (水平布局)。 + * 组件: 两个 `QPushButton`。 + * 文本: 两个按钮的文本都是 "+"。 + * 位置: 位于列表上方,用于“全选”操作(第一次点击,将所有没关联的文件扩展名(显示为空白)设置为应用程序提供的打开方式。如果没有空白内容,或第二次点击,将所有文件全部设置为应用程序提供的打开方式)。 + +* 文件类型列表 (核心组件): + * 组件: `QTableWidget` (表格控件)。 + * 列数: 3列。 + * 表头 (Header): + * 第1列标题: "类型" + * 第2列标题: "uuu" (uuu在运行时进行获取,为当前用户名) + * 第3列标题: "所有用户" + * 行内容示例: + * 第一列:一个文件类型图标,右边跟着对应的文本。表示当前文件扩展名,和当前混合视图(hybrid)下的图标。图标和文本均从wfassoc函数获取。 + * 第二列:用户视图(user)下的名称。文本从wfassoc函数获取。 + * 第三列:系统视图(system)下的名称。文本从wfassoc函数获取。 + * 滚动条: 右侧有一个垂直滚动条 (`QScrollBar`),表示内容超出可视区域。 + * 操作方式: + * 第二列和第三列的元素可点击。 + * 如果元素为空白或其它打开方式,则点击后设置为当前应用程序指定的打开方式(link)。 + * 如果是自身打开方式,点击后设置为空白(unlink) + * 点击后,第一列的图标需要改变,也因此你需要暂存当前应用程序提供打开方式的图标。如果第二第三列均为空,则不显示图标(仍然占位,显示为空白)。 + * 点击操作并不会实时操作注册表,程序需要暂存用户的需求,然后在点击确认或应用按钮后再统一执行。 + +* 底部按钮栏 + * 布局: `QHBoxLayout` (水平布局),通常右对齐或使用 `QDialogButtonBox`。 + * 组件: 三个 `QPushButton`。 + * 按钮文本 (从左到右): + 1. "确定" (通常设为默认按钮 `setDefault(true)`)。 + 2. "取消"。 + 3. "应用":点击后应用修改,并留在页面 (如果没有修改,则不可用)。 + +额外注意: + +* 如果应用程序没有安装,则本页面下所有内容均不启用。 +* 如果启动时命令行指定以为当前用户安装的模式启动,则系统那一栏所有按钮都不可用 + +# 代码要求 + +- 有关wfassoc的接口,请查阅@wfassoc-cdylib/codegen/wfassoc++.h 我要求你使用这个头文件中提供的内容来进行编写。 + - wfassoc++.h文件中没有注释,如果你想查看注释,请访问@wfassoc-cdylib/codegen/wfassoc.h 文件。wfassoc++.h是wfassoc.h的C++包装。 + - wfassoc.h所暴露的接口是由Rust编写的,通常查看wfassoc.h可满足所有需求。如果仍有不确定的内容,可查看其对应Rust项目的源码,位于@wfassoc-cdylib/src 目录下。或更进一步地查看其依赖的源码,位于@wfassoc/src 目录下。 +- 该GUI程序需要接受两个必要的命令行参数,请使用Qt内置的命令行解析器进行解析: + - `-c`或`--manifest`:指定要配置的应用程序的清单文件。 + - `-f`或`--for`:指定应用程序要安装到的 + - 清单文件的样例是@example/manifest/ppic.toml +- 在应用程序加载时,或者执行操作时,如果发生错误(例如底层wfassoc发生错误,丢失命令行选项等,则弹出对话框报错,然后立即退出程序) +- 程序基本流程: + - 接受命令行,检查命令行参数是否合法 + - 加载命令行指定的manifest文件,并使用sanitizer检查错误。你可以阅读@wfassoc-exec/src/manifest.rs 文件来看看我是如何在Rust中检查它的。 + - 按照给定的manifest文件,使用wfassoc库构建schema,然后再构建program。 + - 初始化窗口。 + - 调用wfassoc program提供的函数,检查应用程序是否安装,设置窗口的安装部分的按钮enable。 + - 调用wfassoc program提供的函数,遍历所有文件扩展名和关联情况,设置窗口的文件关联表格。 + - 用户可以在"应用程序"选项卡中注册和卸载应用程序,点击后弹出窗口表示安装或卸载成功,然后检测是否安装,并刷新各个控件的enable状态。 + - 用户可以在"文件关联"选项卡中设置是否以当前应用程序打开某些扩展名。用户可以点击全选按钮或单元格来进行设置,应用程序暂存修改,等用户点击确认或应用后再应用修改。如果点击的是应用,则刷新当前页面。 + +# 额外要求 + +- 不要尝试去编译来检查错误。我会安排其他人来检查程序是否能正常运行,并汇报回来,你再修改。 +- 你不需要关心能否找到Qt,wfassoc和toml11这些库。 + - 对于wfassoc,你只需要将@wfassoc-cdylib/codegen/Findwfassoc.cmake 复制到@example/qwfassoc/cmake 目录下,并在此目录下编写一个README.md,表明这个文件是从哪里复制来的即可。然后把复制的cmake文件所在目录加入find_package目录,然后使用find_package寻找wfassoc即可。至于去哪里找这个库,我会安排其他人来做。 + - 对于Qt和toml11我会安排其他人来做,你只需要用find_package来找他们就行,需要操心能不能找到。 +- 如果你对某项需求有疑问,请问我,而不是进行猜测。 + + + + + + + + + + + +### 总结代码结构示意 (伪代码): + +```cpp +QDialog *dialog = new QDialog(); +dialog->setWindowTitle("选项"); + +QVBoxLayout *mainLayout = new QVBoxLayout(dialog); + +// 1. Tab Widget +QTabWidget *tabWidget = new QTabWidget(); +tabWidget->addTab(new QWidget(), "系统"); +tabWidget->addTab(new QWidget(), "7-Zip"); +// ... 其他 tabs + +// 2. System Tab Content +QWidget *systemTab = tabWidget->widget(0); +QVBoxLayout *systemLayout = new QVBoxLayout(systemTab); + +// Label +QLabel *label = new QLabel("使用 7-Zip 关联的文件类型:"); +systemLayout->addWidget(label); + +// Buttons (+) +QHBoxLayout *btnLayout = new QHBoxLayout(); +QPushButton *btnPlus1 = new QPushButton("+"); +QPushButton *btnPlus2 = new QPushButton("+"); +btnLayout->addWidget(btnPlus1); +btnLayout->addWidget(btnPlus2); +systemLayout->addLayout(btnLayout); + +// List (TreeWidget) +QTreeWidget *treeWidget = new QTreeWidget(); +treeWidget->setColumnCount(3); +treeWidget->setHeaderLabels(QStringList() << "类型" << "yyc12345" << "所有用户"); +// 添加 items... +systemLayout->addWidget(treeWidget); + +// 3. Bottom Buttons +QHBoxLayout *bottomLayout = new QHBoxLayout(); +bottomLayout->addStretch(); // 推挤按钮到右边 +QPushButton *btnOK = new QPushButton("确定"); +QPushButton *btnCancel = new QPushButton("取消"); +QPushButton *btnApply = new QPushButton("应用(A)"); +btnApply->setEnabled(false); // 禁用 +QPushButton *btnHelp = new QPushButton("帮助"); + +bottomLayout->addWidget(btnOK); +bottomLayout->addWidget(btnCancel); +bottomLayout->addWidget(btnApply); +bottomLayout->addWidget(btnHelp); + +mainLayout->addWidget(tabWidget); +mainLayout->addLayout(bottomLayout); +``` + + + + + + + + + +这是一个标准的 Windows 风格属性对话框,可以通过以下 Qt Widgets 结构来描述: + +### 1. 主窗口容器 +* 类: `QDialog`。 +* 标题: "系统属性"。 +* 布局: 垂直布局 (`QVBoxLayout`)。 + +### 2. 顶部选项卡 (Tabs) +* 组件: `QTabWidget`。 +* 标签页: 包含 "计算机名", "硬件", "高级", "系统保护", "远程"。 +* 当前选中: "硬件" 标签页。 + +### 3. "硬件" 选项卡内容 +该选项卡内部使用垂直布局 (`QVBoxLayout`),包含两个主要的分组区域(视觉上类似 `QGroupBox` 或带有边框的 `QFrame`): + +#### 区域 A: 设备管理器 (上半部分) +* 容器: 一个带有边框的容器。 +* 布局: 水平布局 (`QHBoxLayout`)。 + * 左侧: 一个 `QLabel` 显示电脑图标。 + * 中间: 一个 `QLabel` 显示说明文本:"设备管理器列出所有安装在计算机上的硬件设备。请使用设备管理器来更改设备的属性。" (文本需要设置自动换行 `setWordWrap(true)`)。 + * 右侧/底部: 一个 `QPushButton`,文本为 "设备管理器(D)"。 + +#### 区域 B: 设备安装设置 (下半部分) +* 容器: 一个带有边框的容器。 +* 布局: 垂直布局 (`QVBoxLayout`)。 + * 顶部行: 水平布局 (`QHBoxLayout`)。 + * 左侧: 一个 `QLabel` 显示列表/勾选图标。 + * 右侧: 一个 `QLabel` 显示说明文本:"选择 Windows 是否下载制造商提供的可用于你的设备的应用和自定义图标。" (文本需要设置自动换行)。 + * 底部: 一个 `QPushButton`,文本为 "设备安装设置(S)",靠右对齐。 + +### 4. 底部按钮栏 +* 布局: 水平布局 (`QHBoxLayout`),右对齐 (通常通过 `addStretch()` 实现)。 +* 组件: 三个 `QPushButton`。 + * "确定" + * "取消" + * "应用(A)" (注意:截图中该按钮呈灰色,代码中需设置 `setEnabled(false)`)。 diff --git a/example/qwfassoc/README.md b/example/qwfassoc/README.md new file mode 100644 index 0000000..5b223d0 --- /dev/null +++ b/example/qwfassoc/README.md @@ -0,0 +1,3 @@ +# Q WFAssoc + +TODO diff --git a/wfassoc-cdylib/src/lib.rs b/wfassoc-cdylib/src/lib.rs index 62b06c6..8c39661 100644 --- a/wfassoc-cdylib/src/lib.rs +++ b/wfassoc-cdylib/src/lib.rs @@ -24,17 +24,17 @@ enum Error { Program(#[from] wfassoc::highlevel::ProgramError), /// Error when manipulating with C-style string. - #[error("{0}")] + #[error("C-Style string FFI error:{0}")] CStrFfi(#[from] cstr_ffi::Error), /// Error when manipulating with object pool. - #[error("{0}")] + #[error("object pool error: {0}")] ObjectPool(#[from] object_pool::Error), /// Error occurs when checking enum value - #[error("")] + #[error("the enumeration value provided to FFI function is out of its range")] EnumOutOfRange, /// Error when manipulating with poison RwLock - #[error("RwLock is poisoning")] + #[error("concurrency error: RwLock is poisonous")] PoisonRwLock, }