fix(generate): limit gallery preview to left double-click

This commit is contained in:
chengma
2026-07-20 10:12:12 +08:00
parent 391a50a982
commit c81a24d173
4 changed files with 75 additions and 10 deletions
+1 -1
View File
@@ -330,7 +330,7 @@ class GenerateTaskTableModel(QAbstractTableModel):
def _cover_reset_tooltip(self, task): def _cover_reset_tooltip(self, task):
count = self._cover_reset_count(task) count = self._cover_reset_count(task)
return f"该商品封面已重置 {count} 次,可能有多张候选图,双击可查看封面画廊" return f"该商品封面已重置 {count} 次,可能有多张候选图,左键双击可查看封面画廊"
def _has_new_title(self, task): def _has_new_title(self, task):
return bool(str(getattr(task, "new_title", "") or "").strip()) return bool(str(getattr(task, "new_title", "") or "").strip())
+17 -3
View File
@@ -2,7 +2,7 @@
from __future__ import annotations from __future__ import annotations
from PySide6.QtCore import QEvent, QRectF, QSize from PySide6.QtCore import QEvent, QModelIndex, QRectF, QSize, Signal
from PySide6.QtGui import QColor, QPainter from PySide6.QtGui import QColor, QPainter
from ... import product_status from ... import product_status
@@ -16,6 +16,20 @@ def GenerateWorker(*args, **kwargs):
return _call_package_attr("GenerateWorker", _RealGenerateWorker, *args, **kwargs) return _call_package_attr("GenerateWorker", _RealGenerateWorker, *args, **kwargs)
class _GenerateTaskTableView(QTableView):
"""Task table that exposes only left-button double-clicks for previews."""
leftDoubleClicked = Signal(QModelIndex)
def mouseDoubleClickEvent(self, event):
super().mouseDoubleClickEvent(event)
if event.button() != Qt.LeftButton:
return
index = self.indexAt(event.position().toPoint())
if index.isValid():
self.leftDoubleClicked.emit(index)
class _CoverThumbnailLabel(QLabel): class _CoverThumbnailLabel(QLabel):
def __init__(self, image_path, open_callback, parent=None): def __init__(self, image_path, open_callback, parent=None):
super().__init__(parent) super().__init__(parent)
@@ -1158,7 +1172,7 @@ class GenerateTab(QWidget):
) = _build_empty_state_card("generateEmptyStateCard") ) = _build_empty_state_card("generateEmptyStateCard")
if self.open_accounts_callback is not None: if self.open_accounts_callback is not None:
self.empty_state_button.clicked.connect(self.open_accounts_callback) self.empty_state_button.clicked.connect(self.open_accounts_callback)
self.task_table = QTableView() self.task_table = _GenerateTaskTableView()
self.model = GenerateTaskTableModel(self.task_table, db_path=self.db_path, status_callback=self._set_status) self.model = GenerateTaskTableModel(self.task_table, db_path=self.db_path, status_callback=self._set_status)
self.model.set_generate_mode(self._current_generate_mode()) self.model.set_generate_mode(self._current_generate_mode())
self.task_table.setModel(self.model) self.task_table.setModel(self.model)
@@ -1249,7 +1263,7 @@ class GenerateTab(QWidget):
self.generate_button.clicked.connect(self.start_generate) self.generate_button.clicked.connect(self.start_generate)
self.stop_generate_button.clicked.connect(self.stop_generate) self.stop_generate_button.clicked.connect(self.stop_generate)
self.reset_generate_button.clicked.connect(self.reset_generated_result) self.reset_generate_button.clicked.connect(self.reset_generated_result)
self.task_table.doubleClicked.connect(self.show_task_images) self.task_table.leftDoubleClicked.connect(self.show_task_images)
self.refresh_title_templates() self.refresh_title_templates()
self.refresh_cover_templates() self.refresh_cover_templates()
+9 -6
View File
@@ -1,7 +1,7 @@
--- ---
id: T-668 id: T-668
title: AI生成图片画廊仅响应左键双击 title: AI生成图片画廊仅响应左键双击
status: TODO status: DONE
phase: 7 phase: 7
deps: [] deps: []
created: 2026-07-20 created: 2026-07-20
@@ -22,10 +22,10 @@ created: 2026-07-20
## 验收标准 ## 验收标准
- [ ] 左键双击②任务列表的非新标题编辑列时,仍打开当前行的封面图片画廊。 - [x] 左键双击②任务列表的非新标题编辑列时,仍打开当前行的封面图片画廊。
- [ ] 右键双击同一行或空白区域时,不打开图片画廊、不保存或重置任何数据。 - [x] 右键双击同一行或空白区域时,不打开图片画廊、不保存或重置任何数据。
- [ ] 新标题编辑列继续不打开图片画廊;单击选中、键盘上下切换、封面候选图保存及③更新蝦皮不回归。 - [x] 新标题编辑列继续不打开图片画廊;单击选中、键盘上下切换、封面候选图保存及③更新蝦皮不回归。
- [ ] `tests/test_gui.py` 覆盖左键双击会调用预览、右键双击不会调用预览。 - [x] `tests/test_gui.py` 覆盖左键双击会调用预览、右键双击不会调用预览。
## 验证 ## 验证
@@ -43,4 +43,7 @@ git diff --check
## 执行记录 ## 执行记录
- 待实现。 - 新增②专用 `_GenerateTaskTableView`,只为 `Qt.LeftButton` 双击发出 `leftDoubleClicked`;图片画廊改接该信号,移除通用 `doubleClicked` 绑定。
- 保留 Qt 默认双击处理,因此新标题列的既有双击编辑不受影响;右键双击不再触发画廊。封面候选提示统一为「左键双击」。
- 新增 GUI 回归测试,验证右键双击不打开画廊、左键双击仍打开。
- 验证通过:`py -3.10 -m unittest discover -s tests`(620 项)、`py -3.10 -m ruff check app tests main.py`、`py -3.10 -m compileall app main.py`、`git diff --check`。
+48
View File
@@ -3463,6 +3463,54 @@ class GuiTests(TempDirMixin, unittest.TestCase):
self.assert_removed(temp_dir) self.assert_removed(temp_dir)
def test_generate_table_emits_preview_only_for_left_double_click(self):
with self.make_temp_dir() as temp_dir:
cfg = self.make_config(temp_dir)
db.init_db(cfg["db_path"])
batch_id = db.create_batch(["input.xlsx"], path=cfg["db_path"])
db.insert_tasks(
batch_id,
[
{
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
"source_sheet": "商品",
"source_row": 2,
"account_name": "主店",
"alias": "alias-a",
"item_id": "51100639510",
}
],
path=cfg["db_path"],
)
tab = GenerateTab(config=cfg)
self.addCleanup(tab.close)
tab.resize(1000, 600)
tab.show()
QApplication.processEvents()
index = tab.model.index(0, 0)
rect = tab.task_table.visualRect(index)
self.assertTrue(rect.isValid())
previewed_rows = []
tab.task_table.leftDoubleClicked.connect(
lambda clicked_index: previewed_rows.append(clicked_index.row())
)
with mock.patch(
"app.gui.tabs.generate.CoverGalleryDialog.exec",
return_value=0,
) as execute:
QTest.mouseDClick(tab.task_table.viewport(), Qt.RightButton, Qt.NoModifier, rect.center())
QApplication.processEvents()
self.assertEqual([], previewed_rows)
execute.assert_not_called()
QTest.mouseDClick(tab.task_table.viewport(), Qt.LeftButton, Qt.NoModifier, rect.center())
QApplication.processEvents()
self.assertEqual([0], previewed_rows)
execute.assert_called_once()
self.assert_removed(temp_dir)
def test_generate_tab_opens_current_row_image_directory(self): def test_generate_tab_opens_current_row_image_directory(self):
with self.make_temp_dir() as temp_dir: with self.make_temp_dir() as temp_dir:
cfg = self.make_config(temp_dir) cfg = self.make_config(temp_dir)