diff --git a/da_ext_settings.py b/da_ext_settings.py new file mode 100644 index 0000000..00a99b3 --- /dev/null +++ b/da_ext_settings.py @@ -0,0 +1,159 @@ +# coding: utf8 +from PySide6 import QtWidgets, QtCore + + +class PushButtonWithId(QtWidgets.QPushButton): + + clicked_with_id = QtCore.Signal(str) + + def __init__(self, ids: str, parent: QtWidgets.QWidget = None, title: str = ""): + super().__init__(title, parent) + self.ids = ids + self.clicked.connect(self.on_self_clicked) + + def on_self_clicked(self): + self.clicked_with_id.emit(self.ids) + + +class DaExtSettings(QtWidgets.QDialog): + + def __init__(self, parent: QtWidgets.QWidget = None): + super().__init__(parent) + self.setWindowTitle("设置") + + self.vly_m = QtWidgets.QVBoxLayout() + self.setLayout(self.vly_m) + + self.gbx_exec = QtWidgets.QGroupBox("执行文件路径", self) + self.vly_m.addWidget(self.gbx_exec) + + self.gly_gbx_exec = QtWidgets.QGridLayout() + self.gbx_exec.setLayout(self.gly_gbx_exec) + + self.lb_exec_chrome = QtWidgets.QLabel("Chrome", self) + self.lb_exec_edge = QtWidgets.QLabel("Edge", self) + self.lb_exec_brave = QtWidgets.QLabel("Brave", self) + self.lne_exec_chrome = QtWidgets.QLineEdit(self) + self.lne_exec_edge = QtWidgets.QLineEdit(self) + self.lne_exec_brave = QtWidgets.QLineEdit(self) + self.pbn_exec_chrome = PushButtonWithId("ChromeExec", self, "选择") + self.pbn_exec_edge = PushButtonWithId("EdgeExec", self, "选择") + self.pbn_exec_brave = PushButtonWithId("BraveExec", self, "选择") + + self.gly_gbx_exec.addWidget(self.lb_exec_chrome, 0, 0) + self.gly_gbx_exec.addWidget(self.lb_exec_edge, 1, 0) + self.gly_gbx_exec.addWidget(self.lb_exec_brave, 2, 0) + self.gly_gbx_exec.addWidget(self.lne_exec_chrome, 0, 1) + self.gly_gbx_exec.addWidget(self.lne_exec_edge, 1, 1) + self.gly_gbx_exec.addWidget(self.lne_exec_brave, 2, 1) + self.gly_gbx_exec.addWidget(self.pbn_exec_chrome, 0, 2) + self.gly_gbx_exec.addWidget(self.pbn_exec_edge, 1, 2) + self.gly_gbx_exec.addWidget(self.pbn_exec_brave, 2, 2) + + self.gbx_data = QtWidgets.QGroupBox("用户数据路径", self) + self.vly_m.addWidget(self.gbx_data) + + self.gly_gbx_data = QtWidgets.QGridLayout() + self.gbx_data.setLayout(self.gly_gbx_data) + + self.lb_data_chrome = QtWidgets.QLabel("Chrome", self) + self.lb_data_edge = QtWidgets.QLabel("Edge", self) + self.lb_data_brave = QtWidgets.QLabel("Brave", self) + self.lne_data_chrome = QtWidgets.QLineEdit(self) + self.lne_data_edge = QtWidgets.QLineEdit(self) + self.lne_data_brave = QtWidgets.QLineEdit(self) + self.pbn_data_chrome = PushButtonWithId("ChromeData", self, "选择") + self.pbn_data_edge = PushButtonWithId("EdgeData", self, "选择") + self.pbn_data_brave = PushButtonWithId("BraveData", self, "选择") + + self.gly_gbx_data.addWidget(self.lb_data_chrome, 0, 0) + self.gly_gbx_data.addWidget(self.lb_data_edge, 1, 0) + self.gly_gbx_data.addWidget(self.lb_data_brave, 2, 0) + self.gly_gbx_data.addWidget(self.lne_data_chrome, 0, 1) + self.gly_gbx_data.addWidget(self.lne_data_edge, 1, 1) + self.gly_gbx_data.addWidget(self.lne_data_brave, 2, 1) + self.gly_gbx_data.addWidget(self.pbn_data_chrome, 0, 2) + self.gly_gbx_data.addWidget(self.pbn_data_edge, 1, 2) + self.gly_gbx_data.addWidget(self.pbn_data_brave, 2, 2) + + self.hly_bot = QtWidgets.QHBoxLayout() + self.pbn_save = QtWidgets.QPushButton("保存", self) + self.pbn_cancel = QtWidgets.QPushButton("取消", self) + + self.hly_bot.addStretch(1) + self.hly_bot.addWidget(self.pbn_save) + self.hly_bot.addWidget(self.pbn_cancel) + + self.vly_m.addLayout(self.hly_bot) + self.vly_m.addStretch(1) + + self.pbn_save.clicked.connect(self.on_pbn_save_clicked) + self.pbn_cancel.clicked.connect(self.on_pbn_cancel_clicked) + + self.pbn_exec_chrome.clicked_with_id.connect(self.on_pbn_exec_n_clicked_with_id) + self.pbn_exec_edge.clicked_with_id.connect(self.on_pbn_exec_n_clicked_with_id) + self.pbn_exec_brave.clicked_with_id.connect(self.on_pbn_exec_n_clicked_with_id) + + self.pbn_data_chrome.clicked_with_id.connect(self.on_pbn_data_n_clicked_with_id) + self.pbn_data_edge.clicked_with_id.connect(self.on_pbn_data_n_clicked_with_id) + self.pbn_data_brave.clicked_with_id.connect(self.on_pbn_data_n_clicked_with_id) + + self.read_settings() + + def sizeHint(self): + return QtCore.QSize(540, 140) + + def read_settings(self): + us = QtCore.QSettings() + chrome_exec = str(us.value("ChromeExec", "")) + edge_exec = str(us.value("EdgeExec", "")) + brave_exec = str(us.value("BraveExec", "")) + + chrome_data = str(us.value("ChromeData", "")) + edge_data = str(us.value("EdgeData", "")) + brave_data = str(us.value("BraveData", "")) + + self.lne_exec_chrome.setText(chrome_exec) + self.lne_exec_edge.setText(edge_exec) + self.lne_exec_brave.setText(brave_exec) + + self.lne_data_chrome.setText(chrome_data) + self.lne_data_edge.setText(edge_data) + self.lne_data_brave.setText(brave_data) + + def on_pbn_exec_n_clicked_with_id(self, ids: str): + filename, _ = QtWidgets.QFileDialog.getOpenFileName(self, f"选择 {ids}") + if len(filename) == 0: + return + if ids == "ChromeExec": + self.lne_exec_chrome.setText(filename) + elif ids == "EdgeExec": + self.lne_exec_edge.setText(filename) + elif ids == "BraveExec": + self.lne_exec_brave.setText(filename) + + def on_pbn_data_n_clicked_with_id(self, ids: str): + dirname = QtWidgets.QFileDialog.getExistingDirectory(self, f"选择 {ids}") + if len(dirname) == 0: + return + if ids == "ChromeData": + self.lne_data_chrome.setText(dirname) + elif ids == "EdgeData": + self.lne_data_edge.setText(dirname) + elif ids == "BraveData": + self.lne_data_brave.setText(dirname) + + def on_pbn_save_clicked(self): + us = QtCore.QSettings() + us.setValue("ChromeExec", self.lne_exec_chrome.text()) + us.setValue("EdgeExec", self.lne_exec_edge.text()) + us.setValue("BraveExec", self.lne_exec_brave.text()) + + us.setValue("ChromeData", self.lne_data_chrome.text()) + us.setValue("EdgeData", self.lne_data_edge.text()) + us.setValue("BraveData", self.lne_data_brave.text()) + + self.accept() + + def on_pbn_cancel_clicked(self): + self.reject() diff --git a/da_show_profiles.py b/da_show_profiles.py new file mode 100644 index 0000000..3075431 --- /dev/null +++ b/da_show_profiles.py @@ -0,0 +1,157 @@ +# coding: utf8 +import os +from pathlib import Path +from PySide6 import QtWidgets, QtCore, QtGui +from util_ext import ProfilesData, DeleteThread, DeleteThreadManager +from global_vars import accept_warning + + +def sort_profiles_id_func(profile_id: str) -> int: + if profile_id == "Default": + return 0 + else: + seq = profile_id.split(" ", 1)[-1] + try: + return int(seq) + except ValueError: + # if the id is weird + return 999 + + +class ProfilesModel(QtCore.QAbstractTableModel): + + def __init__(self, + profiles_data: ProfilesData, + ext_id: str, + profiles: list[str], + parent=None): + super().__init__(parent) + self.ext_id = ext_id + self.profiles = profiles + self.profiles.sort(key=sort_profiles_id_func) + self.profiles_data = profiles_data + + def rowCount(self, parent: QtCore.QModelIndex = ...): + return len(self.profiles) + + def columnCount(self, parent: QtCore.QModelIndex = ...): + return 2 + + def data(self, index: QtCore.QModelIndex, role: int = ...): + row = index.row() + col = index.column() + + if col == 0: + if role == QtCore.Qt.ItemDataRole.DisplayRole: + return self.profiles[row] + elif col == 1: + if role == QtCore.Qt.ItemDataRole.DisplayRole: + return self.profiles_data[self.profiles[row]].name + + def headerData(self, section: int, orientation: QtCore.Qt.Orientation, role: int = ...): + if role == QtCore.Qt.ItemDataRole.DisplayRole: + if section == 0: + return "ID" + if section == 1: + return "名称" + + +class DaShowProfiles(QtWidgets.QDialog): + + def __init__(self, + browser: str, + is_chrome_compat: bool, + profiles_data: ProfilesData, + ext_id: str, + ext_name: str, + ext_icon: QtGui.QIcon, + profiles: list[str], + parent: QtWidgets.QWidget = None): + super().__init__(parent) + self.setWindowTitle(ext_name) + self.setWindowIcon(ext_icon) + self.browser = browser + self.is_chrome_compat = is_chrome_compat + + self.process = QtCore.QProcess(self) + + # ========== UI ============== + + self.vly_m = QtWidgets.QVBoxLayout() + self.setLayout(self.vly_m) + + self.lne_info = QtWidgets.QLineEdit(ext_id, self) + self.lne_info.setReadOnly(True) + self.vly_m.addWidget(self.lne_info) + + self.trv_profiles = QtWidgets.QTreeView(self) + self.trv_profiles.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection) + self.vly_m.addWidget(self.trv_profiles) + + self.pgb_del = QtWidgets.QProgressBar(self) + self.pgb_del.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.vly_m.addWidget(self.pgb_del) + + self.hly_bot = QtWidgets.QHBoxLayout() + self.pbn_delete_selected = QtWidgets.QPushButton("删除所选", self) + self.pbn_open = QtWidgets.QPushButton("打开", self) + self.pbn_cancel = QtWidgets.QPushButton("取消", self) + self.hly_bot.addWidget(self.pbn_delete_selected) + self.hly_bot.addStretch(1) + self.hly_bot.addWidget(self.pbn_open) + self.hly_bot.addWidget(self.pbn_cancel) + self.vly_m.addLayout(self.hly_bot) + + self.profiles_model = ProfilesModel(profiles_data, ext_id, profiles, self) + self.trv_profiles.setModel(self.profiles_model) + + self.pbn_delete_selected.clicked.connect(self.on_pbn_delete_selected_clicked) + self.pbn_open.clicked.connect(self.on_pbn_open_clicked) + self.pbn_cancel.clicked.connect(self.reject) + + def sizeHint(self): + return QtCore.QSize(400, 360) + + def on_pbn_open_clicked(self): + us = QtCore.QSettings() + exec_path = str(us.value(f"{self.browser}Exec", "")) + if len(exec_path) == 0 or not os.path.exists(exec_path): + QtWidgets.QMessageBox.critical(self, "错误", f"无法找到 {self.browser} 浏览器的执行路径") + return + + indexes = self.trv_profiles.selectedIndexes() + cmd = rf'"{exec_path}" --profile-directory="{{0}}"' + for idx in indexes: + if idx.column() != 0: + continue + profile_id = self.profiles_model.data(idx, QtCore.Qt.ItemDataRole.DisplayRole) + # setProgram 不行,不知道为什么,莫名其妙 + self.process.startCommand(cmd.format(profile_id)) + self.process.waitForFinished(10000) + + def on_pbn_delete_selected_clicked(self): + us = QtCore.QSettings() + user_data_path = str(us.value(f"{self.browser}Data", "")) + if self.browser == "Chrome" and self.is_chrome_compat: + pref_name = "Preferences" + else: + pref_name = "Secure Preferences" + + indexes = self.trv_profiles.selectedIndexes() + total = len(indexes) // 2 + if accept_warning(self, True, "警告", f"确定要删除这 {total} 项吗?"): + return + + del_thd_mgr = DeleteThreadManager(total, self.pgb_del, self) + + for idx in indexes: + if idx.column() != 0: + continue + profile_id = self.profiles_model.data(idx, QtCore.Qt.ItemDataRole.DisplayRole) + del_thd = DeleteThread( + str(Path(user_data_path, profile_id)), + pref_name, + [self.lne_info.text()], + self + ) + del_thd_mgr.start(del_thd) diff --git a/main.py b/main.py index a6cd018..fbdec6c 100644 --- a/main.py +++ b/main.py @@ -1,15 +1,63 @@ # coding: utf8 +import os import sys -from PySide6 import QtWidgets +from pathlib import Path +from PySide6 import QtWidgets, QtCore from mw_dailycheck import MwDailyCheck import daily_check_rc version = (0, 1, 0) +ORG_NAME = "JnPrograms" +APP_NAME = "DailyCheck" + + +def set_default_settings(): + plat = sys.platform + user_path = os.path.expanduser("~") + user_data_path_map = { + "win32": { + "Chrome": Path(user_path, r"AppData\Local\Google\Chrome\User Data"), + "Edge": Path(user_path, r"AppData\Local\Microsoft\Edge\User Data"), + "Brave": Path(user_path, r"AppData\Local\BraveSoftware\Brave-Browser\User Data"), + }, + "darwin": { + "Chrome": Path(user_path, "Library/Application Support/Google/Chrome"), + "Edge": Path(user_path, "Library/Application Support/Microsoft Edge"), + "Brave": Path(user_path, "Library/Application Support/BraveSoftware/Brave-Browser"), + }, + } + exec_path_map = { + "win32": { + "Chrome": r"C:\Program Files\Google\Chrome\Application\chrome.exe", + "Edge": r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe", + "Brave": r"C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe", + }, + "darwin": { + "Chrome": r"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", + "Edge": r"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge", + "Brave": r"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser", + }, + } + user_data_path = user_data_path_map[plat] + exec_path = exec_path_map[plat] + us = QtCore.QSettings() + us.setValue("ChromeExec", exec_path["Chrome"]) + us.setValue("EdgeExec", exec_path["Edge"]) + us.setValue("BraveExec", exec_path["Brave"]) + us.setValue("ChromeData", user_data_path["Chrome"]) + us.setValue("EdgeData", user_data_path["Edge"]) + us.setValue("BraveData", user_data_path["Brave"]) + def main(): app = QtWidgets.QApplication(sys.argv) + app.setOrganizationName(ORG_NAME) + app.setApplicationName(APP_NAME) + + set_default_settings() + win = MwDailyCheck(version) win.show() return app.exec() diff --git a/mw_dailycheck.py b/mw_dailycheck.py index 96117f9..c3a59aa 100644 --- a/mw_dailycheck.py +++ b/mw_dailycheck.py @@ -96,6 +96,5 @@ class MwDailyCheck(QtWidgets.QMainWindow): } unknown_all.update(unknown_isp_manu) - with open(ex_file, "w", encoding="utf8") as f: - json.dump(unknown_all, f, indent=4, ensure_ascii=False) + ex_file.write_text(json.dumps(unknown_all, indent=4, ensure_ascii=False), "utf8") QtWidgets.QMessageBox.information(self, "提示", f"已导出到 {ex_file}") diff --git a/util_ext.py b/util_ext.py index 1ab85d1..a03e301 100644 --- a/util_ext.py +++ b/util_ext.py @@ -1,31 +1,14 @@ # coding: utf8 import os -import sys import json +import shutil from pathlib import Path +# from typing import Callable +from PySide6 import QtCore, QtWidgets from dataclasses import dataclass, field from global_vars import get_with_chained_keys -PLAT = sys.platform -USER_PATH = os.path.expanduser("~") - -USER_DATA_PATH_MAP = { - "win32": { - "Chrome": Path(USER_PATH, "AppData", "Local", "Google", "Chrome", "User Data"), - "Edge": Path(USER_PATH, "AppData", "Local", "Microsoft", "Edge", "User Data"), - "Brave": Path(USER_PATH, "AppData", "Local", "BraveSoftware", "Brave-Browser", "User Data"), - }, - "darwin": { - "Chrome": Path(USER_PATH, "Library", "Application Support", "Google", "Chrome"), - "Edge": Path(USER_PATH, "Library", "Application Support", "Microsoft Edge"), - "Brave": Path(USER_PATH, "Library", "Application Support", "BraveSoftware", "Brave-Browser"), - }, -} - -USER_DATA_PATH = USER_DATA_PATH_MAP[PLAT] - - @dataclass class ProfileNode(object): gaia_given_name: str @@ -38,8 +21,11 @@ class ProfileNode(object): ProfilesData = dict[str, ProfileNode] -def scan_profiles(browser: str) -> ProfilesData: - local_state_path = Path(USER_DATA_PATH[browser], "Local State") +def scan_profiles(user_data_path: str) -> ProfilesData: + local_state_path = Path(user_data_path, "Local State") + if not local_state_path.exists(): + return {} + local_state_data: dict = json.loads(local_state_path.read_text(encoding="utf8")) info_cache_data: dict = get_with_chained_keys(local_state_data, ["profile", "info_cache"]) @@ -61,6 +47,7 @@ def scan_profiles(browser: str) -> ProfilesData: @dataclass class ExtensionNode(object): + # ids: str icon: str name: str # path: str @@ -86,18 +73,22 @@ def get_extension_icon_path(ext_icons: dict[str, str], ext_path: str, profile_pa return str(full_path) -def scan_extensions(browser: str, is_chrome_compat=False) -> ExtensionsData: - profile_data = scan_profiles(browser) +def scan_extensions(browser: str, is_chrome_compat=False) -> tuple[ExtensionsData, ProfilesData]: + us = QtCore.QSettings() + user_data_path = str(us.value(f"{browser}Data", "")) + if len(user_data_path) == 0 or not Path(user_data_path).exists(): + return {}, {} + + profile_data = scan_profiles(user_data_path) extensions_data: ExtensionsData = {} - browser_data_path = USER_DATA_PATH[browser] if browser == "Chrome" and is_chrome_compat: pref_file = "Preferences" else: pref_file = "Secure Preferences" for profile_id in profile_data: - profile_path = Path(browser_data_path, profile_id) + profile_path = Path(user_data_path, profile_id) secure_pref_path = Path(profile_path, pref_file) secure_pref_data: dict = json.loads(secure_pref_path.read_text(encoding="utf8")) ext_settings_data: dict = get_with_chained_keys(secure_pref_data, ["extensions", "settings"], dict()) @@ -122,6 +113,7 @@ def scan_extensions(browser: str, is_chrome_compat=False) -> ExtensionsData: if ext_id not in extensions_data: ext_node = ExtensionNode( + # ids=ext_id, icon=get_extension_icon_path(ext_manifest.get("icons", {}), ext_path, profile_path), name=ext_manifest.get("name", ""), # path=ext_data.get("path", ""), @@ -132,4 +124,110 @@ def scan_extensions(browser: str, is_chrome_compat=False) -> ExtensionsData: ext_node = extensions_data[ext_id] ext_node.profiles += [profile_id] - return extensions_data + return extensions_data, profile_data + + +# ================== Deletion ==================== + + +def delete_extensions(profile_path: str, pref_name: str, ext_ids: list[str]) -> tuple[int, int]: + total = len(ext_ids) + + e_pref_path = Path(profile_path, pref_name) + e_pref_data = json.loads(e_pref_path.read_text("utf8")) # type: dict + ext_set_data = get_with_chained_keys(e_pref_data, ["extensions", "settings"]) # type: dict + if ext_set_data is None: + return 0, total + + s_pref_path = Path(profile_path, "Secure Preferences") + pref_path = Path(profile_path, "Preferences") + s_pref_data = json.loads(s_pref_path.read_text("utf8")) # type: dict + pref_data = json.loads(pref_path.read_text("utf8")) # type: dict + + macs = get_with_chained_keys(s_pref_data, ["protection", "macs", "extensions", "settings"]) # type: dict + if macs is None: + return 0, total + + success = 0 + for ids in ext_ids: + c1 = ext_set_data.pop(ids, None) + c2 = macs.pop(ids, None) + if None not in (c1, c2): + success += 1 + + pinned_ext = get_with_chained_keys(pref_data, ["extensions", "pinned_extensions"]) # type: list + if pinned_ext is not None: + for ids in ext_ids: + if ids in pinned_ext: + pinned_ext.remove(ids) + + s_pref_path.write_text(json.dumps(s_pref_data, ensure_ascii=False), "utf8") + pref_path.write_text(json.dumps(pref_data, ensure_ascii=False), "utf8") + + extensions_path_d = Path(profile_path, "Extensions") + for ids in ext_ids: + # 对于离线安装的插件,目录可能不在这个位置,所以就不删了 + ext_folder_path = Path(extensions_path_d, ids) + if ext_folder_path.exists(): + shutil.rmtree(ext_folder_path, ignore_errors=True) + + return success, total + + +class DeleteThread(QtCore.QThread): + + deleted = QtCore.Signal(int, int) + + def __init__(self, + profile_path: str, + pref_name: str, + ext_ids: list[str], + parent: QtCore.QObject = None): + super().__init__(parent) + self.profile_path = profile_path + self.pref_name = pref_name + self.ext_ids = ext_ids + self.finished.connect(self.deleteLater) + + def run(self): + success, total = delete_extensions(self.profile_path, self.pref_name, self.ext_ids) + self.deleted.emit(success, total) + + +class DeleteThreadManager(QtCore.QObject): + + def __init__(self, total: int, progress_bar: QtWidgets.QProgressBar, parent: QtWidgets.QDialog): + super().__init__(parent) + self.deletion_progress = 0 + self.success_deletion = 0 + self.fail_deletion = 0 + self.total_for_deletion = total + self.deletion_info = "成功:{success} 个;失败:{fail} 个;总共 {total} 个。" + self.progress_bar = progress_bar + self.parent = parent + + self.progress_bar.setMaximum(total) + self.progress_bar.setValue(0) + + self.progress_bar.valueChanged.connect(self.on_pgb_del_value_changed) + + def start(self, thread: DeleteThread): + thread.deleted.connect(self.on_del_thd_deleted) + thread.start() + + def on_del_thd_deleted(self, success: int, total: int): + self.success_deletion += success + self.deletion_progress += total + self.fail_deletion += total - success + self.progress_bar.setValue(self.deletion_progress) + + def on_pgb_del_value_changed(self, value: int): + if value == self.total_for_deletion: + QtWidgets.QMessageBox.information( + self.parent, "删除结果", self.deletion_info.format( + success=self.success_deletion, + fail=self.fail_deletion, + total=self.total_for_deletion + ) + ) + self.parent.accept() diff --git a/wg_extensions.py b/wg_extensions.py index be81053..5394a39 100644 --- a/wg_extensions.py +++ b/wg_extensions.py @@ -1,10 +1,12 @@ # coding: utf8 from PySide6 import QtWidgets, QtCore, QtGui -from util_ext import scan_extensions, ExtensionsData +from util_ext import scan_extensions, ExtensionsData, ProfilesData from global_vars import ( ExtensionStatusRole, ExtensionIdRole, ) +from da_ext_settings import DaExtSettings +from da_show_profiles import DaShowProfiles class UiWgExtensions(object): @@ -24,6 +26,7 @@ class UiWgExtensions(object): self.cbx_unknown.setChecked(True) self.cbx_chrome_compat = QtWidgets.QCheckBox("谷歌兼容模式", window) self.pbn_update = QtWidgets.QPushButton("更新", window) + self.pbn_settings = QtWidgets.QPushButton("设置", window) self.hly_top.addWidget(self.cmbx_browsers) self.hly_top.addWidget(self.cbx_safe) self.hly_top.addWidget(self.cbx_unsafe) @@ -31,6 +34,7 @@ class UiWgExtensions(object): self.hly_top.addStretch(1) self.hly_top.addWidget(self.cbx_chrome_compat) self.hly_top.addWidget(self.pbn_update) + self.hly_top.addWidget(self.pbn_settings) self.lv_extensions = QtWidgets.QListView(window) self.vly_m.addWidget(self.lv_extensions) @@ -40,6 +44,7 @@ class BaseExtensionsListModel(QtCore.QAbstractListModel): def __init__(self, parent=None): super().__init__(parent) + self.all_profiles = {} # type: ProfilesData self.all_extensions = {} # type: ExtensionsData self.names = [] # type: list[tuple[str, str]] self.icons = {} # type: dict[str, QtGui.QIcon] @@ -51,11 +56,12 @@ class BaseExtensionsListModel(QtCore.QAbstractListModel): def update_ext(self, browser: str, is_chrome_compat=False): """内部用""" + self.all_profiles.clear() self.all_extensions.clear() self.names.clear() self.icons.clear() - self.all_extensions = scan_extensions(browser, is_chrome_compat) + self.all_extensions, self.all_profiles = scan_extensions(browser, is_chrome_compat) for ext_id in self.all_extensions: name = self.all_extensions[ext_id].name icon = self.all_extensions[ext_id].icon @@ -168,6 +174,12 @@ class WgExtensions(QtWidgets.QWidget): self.ui.cbx_unsafe.clicked.connect(self.on_cbx_unsafe_clicked) self.ui.cbx_unknown.clicked.connect(self.on_cbx_unknown_clicked) self.ui.pbn_update.clicked.connect(self.on_pbn_update_clicked) + self.ui.pbn_settings.clicked.connect(self.on_pbn_settings_clicked) + self.ui.lv_extensions.doubleClicked.connect(self.on_lv_extensions_double_clicked) + + def on_pbn_settings_clicked(self): + da_es = DaExtSettings(self) + da_es.exec() def get_current_browser(self) -> str: return self.ui.cmbx_browsers.currentData(QtCore.Qt.ItemDataRole.DisplayRole) @@ -225,6 +237,22 @@ class WgExtensions(QtWidgets.QWidget): def on_pbn_update_clicked(self): self.update_model(self.get_current_browser()) + def on_lv_extensions_double_clicked(self, index: QtCore.QModelIndex): + model = self.ext_list_models[self.get_current_browser()] + ext_id = model.data(index, ExtensionIdRole) + node = model.all_extensions[ext_id] + da_sp = DaShowProfiles( + self.get_current_browser(), + self.ui.cbx_chrome_compat.isChecked(), + model.all_profiles, + ext_id, + node.name, + model.icons[ext_id], + node.profiles, + self + ) + da_sp.exec() + def update_safe(self, safe_info: dict): for browser in self.ext_list_models: self.ext_list_models[browser].update_safe_info(safe_info)