From dc96e1a747a687d9d4ac59babee3e6702c8e1c31 Mon Sep 17 00:00:00 2001 From: Julian Freeman Date: Fri, 19 Jul 2024 20:27:56 -0400 Subject: [PATCH] =?UTF-8?q?dev:=20=E6=94=AF=E6=8C=81=E6=A0=87=E8=AE=B0?= =?UTF-8?q?=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/db_columns_def.py | 9 ++++- lib/kps_operations.py | 4 +-- src/page_query.py | 80 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 83 insertions(+), 10 deletions(-) diff --git a/lib/db_columns_def.py b/lib/db_columns_def.py index 79198e0..ced3f8e 100644 --- a/lib/db_columns_def.py +++ b/lib/db_columns_def.py @@ -12,6 +12,7 @@ columns_d = { "uuid": Column("uuid", DataType.TEXT, nullable=False), "filepath": Column("filepath", DataType.BLOB, nullable=False), "path": Column("path", DataType.BLOB), + "status": Column("status", DataType.TEXT), # 只有三种状态:keep, transfer, delete } all_columns = [ @@ -25,13 +26,19 @@ all_columns = [ columns_d["uuid"], columns_d["filepath"], columns_d["path"], + columns_d["status"], ] +# 插入数据时使用的列 +insert_columns = all_columns[1:-1] + +# 查询数据时使用的列 query_columns = [ columns_d["entry_id"], columns_d["title"], columns_d["username"], columns_d["url"], + columns_d["status"], ] # 从数据库中读取 UUID 和 文件路径分析相似度 @@ -41,5 +48,5 @@ sim_columns = [ ] filepath_col = columns_d["filepath"] - entry_id_col = columns_d["entry_id"] +status_col = columns_d["status"] diff --git a/lib/kps_operations.py b/lib/kps_operations.py index 3ccdbce..6f90134 100644 --- a/lib/kps_operations.py +++ b/lib/kps_operations.py @@ -1,7 +1,7 @@ # coding: utf8 from os import PathLike from pykeepass import PyKeePass -from lib.db_columns_def import all_columns +from lib.db_columns_def import insert_columns from .Sqlite3Helper import Sqlite3Worker, BlobType @@ -46,5 +46,5 @@ def read_kps_to_db(kps_file: str | PathLike[str], password: str, blob_fy("::".join(entry.path[:-1])), ]) - sqh.insert_into(table_name, all_columns[1:], values) + sqh.insert_into(table_name, insert_columns, values) return kp diff --git a/src/page_query.py b/src/page_query.py index f388053..efd0e0a 100644 --- a/src/page_query.py +++ b/src/page_query.py @@ -1,10 +1,10 @@ # coding: utf8 import json -from PySide6 import QtWidgets, QtCore +from PySide6 import QtWidgets, QtCore, QtGui from .da_entry_info import DaEntryInfo -from lib.Sqlite3Helper import Sqlite3Worker, Expression -from lib.db_columns_def import query_columns +from lib.Sqlite3Helper import Sqlite3Worker, Expression, Operand +from lib.db_columns_def import query_columns, status_col, entry_id_col class QueryTableModel(QtCore.QAbstractTableModel): @@ -14,6 +14,25 @@ class QueryTableModel(QtCore.QAbstractTableModel): self.query_results = query_results self.headers = ["序号", "标题", "用户名", "URL"] + self.light_status_colors = { + "keep": QtGui.QBrush(QtGui.QColor("lightgreen")), + "transfer": QtGui.QBrush(QtGui.QColor("moccasin")), + "delete": QtGui.QBrush(QtGui.QColor("pink")), + "none": QtGui.QBrush(QtCore.Qt.GlobalColor.transparent) + } + self.dark_status_colors = { + "keep": QtGui.QBrush(QtGui.QColor("green")), + "transfer": QtGui.QBrush(QtGui.QColor("orange")), + "delete": QtGui.QBrush(QtGui.QColor("orangered")), + "none": QtGui.QBrush(QtCore.Qt.GlobalColor.transparent) + } + if QtWidgets.QApplication.style().name() == "windowsvista": + self.status_colors = self.light_status_colors + elif QtWidgets.QApplication.styleHints().colorScheme() == QtCore.Qt.ColorScheme.Dark: + self.status_colors = self.dark_status_colors + else: + self.status_colors = self.light_status_colors + def rowCount(self, parent: QtCore.QModelIndex = ...): return len(self.query_results) @@ -26,6 +45,14 @@ class QueryTableModel(QtCore.QAbstractTableModel): if isinstance(item, bytes): return item.decode("utf-8") return item + if role == QtCore.Qt.ItemDataRole.BackgroundRole: + status = self.query_results[index.row()][-1] # 最后一列是状态 + if status is None: + status = "none" + return self.status_colors[status] + if role == QtCore.Qt.ItemDataRole.TextAlignmentRole: + if index.column() == 0: + return QtCore.Qt.AlignmentFlag.AlignRight | QtCore.Qt.AlignmentFlag.AlignVCenter def headerData(self, section: int, orientation: QtCore.Qt.Orientation, role: int = ...): if orientation == QtCore.Qt.Orientation.Horizontal: @@ -39,6 +66,19 @@ class PageQuery(QtWidgets.QWidget): self.sqh = sqh self.config = config + # 右键菜单 + self.menu_ctx = QtWidgets.QMenu(self) + self.act_keep = ActionWithStr("keep", "保留", self) + self.act_transfer = ActionWithStr("transfer", "转移", self) + self.act_delete = ActionWithStr("delete", "删除", self) + self.menu_ctx.addActions([self.act_keep, self.act_transfer, self.act_delete]) + + self.act_keep.triggered_with_str.connect(self.on_act_mark_triggered_with_str) + self.act_transfer.triggered_with_str.connect(self.on_act_mark_triggered_with_str) + self.act_delete.triggered_with_str.connect(self.on_act_mark_triggered_with_str) + + # 主布局 + self.hly_m = QtWidgets.QHBoxLayout() self.setLayout(self.hly_m) @@ -64,12 +104,15 @@ class PageQuery(QtWidgets.QWidget): self.vly_sa_wg.addWidget(self.pbn_read_filters) self.trv_m = QtWidgets.QTreeView(self) + self.trv_m.setSelectionMode(QtWidgets.QTreeView.SelectionMode.ExtendedSelection) + self.trv_m.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu) # self.trv_m.setSortingEnabled(True) self.hly_m.addWidget(self.trv_m) self.pbn_all.clicked.connect(self.on_pbn_all_clicked) self.pbn_read_filters.clicked.connect(self.on_pbn_read_filters_clicked) self.trv_m.doubleClicked.connect(self.on_trv_m_double_clicked) + self.trv_m.customContextMenuRequested.connect(self.on_trv_m_custom_context_menu_requested) self.set_default_filters() @@ -123,13 +166,23 @@ class PageQuery(QtWidgets.QWidget): self.trv_m.setModel(model) def on_trv_m_double_clicked(self, index: QtCore.QModelIndex): - model = index.model() - row = index.row() - entry_id_index = model.index(row, 0) - entry_id = entry_id_index.data(QtCore.Qt.ItemDataRole.DisplayRole) + entry_id = index.siblingAtColumn(0).data(QtCore.Qt.ItemDataRole.DisplayRole) da_entry_info = DaEntryInfo(entry_id, self.config, self.sqh, self) da_entry_info.exec() + def on_trv_m_custom_context_menu_requested(self, pos: QtCore.QPoint): + self.menu_ctx.exec(self.trv_m.viewport().mapToGlobal(pos)) + + def on_act_mark_triggered_with_str(self, info: str): + indexes = self.trv_m.selectedIndexes() + entry_ids = [ + index.data(QtCore.Qt.ItemDataRole.DisplayRole) + for index in indexes if index.column() == 0 + ] + + self.sqh.update(self.config["table_name"], [(status_col, info)], + where=Operand(entry_id_col).in_(entry_ids)) + class PushButtonWithData(QtWidgets.QPushButton): @@ -142,3 +195,16 @@ class PushButtonWithData(QtWidgets.QPushButton): def on_self_clicked(self): self.clicked_with_data.emit(self.data) + + +class ActionWithStr(QtGui.QAction): + + triggered_with_str = QtCore.Signal(str) + + def __init__(self, info: str, title: str, parent: QtWidgets.QWidget = None): + super().__init__(title, parent) + self.info = info + self.triggered.connect(self.on_self_triggered) + + def on_self_triggered(self): + self.triggered_with_str.emit(self.info)