gui 新增重置設定功能,允許用戶清除所有已保存的設定並恢復到預設狀態

This commit is contained in:
Minidoracat 2025-06-03 16:43:36 +08:00
parent ac05fd5b9a
commit be4d1b3a64
8 changed files with 599 additions and 215 deletions

View File

@ -9,6 +9,7 @@ GUI 主要入口點
from typing import Optional
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtGui import QFont
import sys
from .models import FeedbackResult
@ -31,6 +32,17 @@ def feedback_ui(project_directory: str, summary: str) -> Optional[FeedbackResult
if app is None:
app = QApplication(sys.argv)
# 設定全域微軟正黑體字體
font = QFont("Microsoft JhengHei", 11) # 微軟正黑體11pt
app.setFont(font)
# 設定字體回退順序,確保中文字體正確顯示
app.setStyleSheet("""
* {
font-family: "Microsoft JhengHei", "微軟正黑體", "Microsoft YaHei", "微软雅黑", "SimHei", "黑体", sans-serif;
}
""")
# 創建主窗口
window = FeedbackWindow(project_directory, summary)
window.show()

View File

@ -9,18 +9,21 @@
from PySide6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QGroupBox, QComboBox, QRadioButton, QButtonGroup, QMessageBox,
QCheckBox
QComboBox, QRadioButton, QButtonGroup, QMessageBox,
QCheckBox, QPushButton, QFrame
)
from PySide6.QtCore import Signal
from PySide6.QtCore import Signal, Qt
from PySide6.QtGui import QFont
from ...i18n import t, get_i18n_manager
from ...debug import gui_debug_log as debug_log
class SettingsTab(QWidget):
"""設置分頁組件"""
language_changed = Signal()
layout_change_requested = Signal(bool, str) # 佈局變更請求信號 (combined_mode, orientation)
reset_requested = Signal() # 重置設定請求信號
def __init__(self, combined_mode: bool, config_manager, parent=None):
super().__init__(parent)
@ -28,315 +31,557 @@ class SettingsTab(QWidget):
self.config_manager = config_manager
self.layout_orientation = self.config_manager.get_layout_orientation()
self.i18n = get_i18n_manager()
# 保存需要更新的UI元素引用
self.ui_elements = {}
# 設置全域字體為微軟正黑體
self._setup_font()
self._setup_ui()
# 在UI設置完成後確保正確設置初始狀態
self._set_initial_layout_state()
def _setup_font(self) -> None:
"""設置全域字體"""
font = QFont("Microsoft JhengHei", 9) # 微軟正黑體,調整為 9pt
self.setFont(font)
# 設置整個控件的樣式表,確保中文字體正確
self.setStyleSheet("""
QWidget {
font-family: "Microsoft JhengHei", "微軟正黑體", sans-serif;
}
""")
def _setup_ui(self) -> None:
"""設置用戶介面"""
layout = QVBoxLayout(self)
layout.setSpacing(16)
layout.setContentsMargins(16, 16, 16, 16)
# 主容器
main_layout = QHBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.setSpacing(0)
# === 語言設置區域 ===
self.language_group = QGroupBox(t('settings.language.title'))
self.language_group.setObjectName('language_group')
language_layout = QVBoxLayout(self.language_group)
language_layout.setSpacing(12)
language_layout.setContentsMargins(16, 16, 16, 16)
# 左側內容區域
content_widget = QWidget()
content_widget.setMaximumWidth(600)
content_layout = QVBoxLayout(content_widget)
content_layout.setContentsMargins(20, 20, 20, 20)
content_layout.setSpacing(16)
# 語言選擇器
language_row = QHBoxLayout()
# === 語言設置 ===
self._create_language_section(content_layout)
self.language_label = QLabel(t('settings.language.selector'))
self.language_label.setStyleSheet("font-weight: bold; color: #e0e0e0; font-size: 14px;")
language_row.addWidget(self.language_label)
# 添加分隔線
self._add_separator(content_layout)
# === 界面佈局 ===
self._create_layout_section(content_layout)
# 添加分隔線
self._add_separator(content_layout)
# === 視窗設置 ===
self._create_window_section(content_layout)
# 添加分隔線
self._add_separator(content_layout)
# === 重置設定 ===
self._create_reset_section(content_layout)
# 添加彈性空間
content_layout.addStretch()
# 添加到主布局
main_layout.addWidget(content_widget)
main_layout.addStretch() # 右側彈性空間
# 設定初始狀態
self._set_initial_layout_state()
def _add_separator(self, layout: QVBoxLayout) -> None:
"""添加分隔線"""
separator = QFrame()
separator.setFrameShape(QFrame.HLine)
separator.setStyleSheet("""
QFrame {
color: #444444;
background-color: #444444;
border: none;
height: 1px;
margin: 6px 0px;
}
""")
layout.addWidget(separator)
def _create_section_header(self, title: str, emoji: str = "") -> QLabel:
"""創建區塊標題"""
text = f"{emoji} {title}" if emoji else title
label = QLabel(text)
label.setStyleSheet("""
QLabel {
font-family: "Microsoft JhengHei", "微軟正黑體", sans-serif;
font-size: 16px;
font-weight: bold;
color: #ffffff;
margin-bottom: 6px;
margin-top: 2px;
}
""")
return label
def _create_description(self, text: str) -> QLabel:
"""創建說明文字"""
label = QLabel(text)
label.setStyleSheet("""
QLabel {
font-family: "Microsoft JhengHei", "微軟正黑體", sans-serif;
color: #aaaaaa;
font-size: 12px;
margin-bottom: 12px;
line-height: 1.3;
}
""")
label.setWordWrap(True)
return label
def _create_language_section(self, layout: QVBoxLayout) -> None:
"""創建語言設置區域"""
header = self._create_section_header(t('settings.language.title'), "🌐")
layout.addWidget(header)
# 保存引用以便更新
self.ui_elements['language_header'] = header
desc = self._create_description(t('settings.language.description'))
layout.addWidget(desc)
# 保存引用以便更新
self.ui_elements['language_desc'] = desc
# 語言選擇器容器
lang_container = QHBoxLayout()
lang_container.setContentsMargins(0, 0, 0, 0)
self.language_selector = QComboBox()
self.language_selector.setMinimumWidth(180)
self.language_selector.setMinimumHeight(35)
self.language_selector.setMinimumHeight(28)
self.language_selector.setMaximumWidth(140)
self.language_selector.setStyleSheet("""
QComboBox {
background-color: #404040;
border: 1px solid #606060;
font-family: "Microsoft JhengHei", "微軟正黑體", sans-serif;
background-color: #3a3a3a;
border: 1px solid #555555;
border-radius: 4px;
padding: 8px 12px;
color: #e0e0e0;
font-size: 14px;
padding: 4px 8px;
color: #ffffff;
font-size: 12px;
}
QComboBox:hover {
border-color: #0078d4;
}
QComboBox::drop-down {
border: none;
width: 25px;
width: 20px;
}
QComboBox::down-arrow {
image: none;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 7px solid #e0e0e0;
margin-right: 6px;
image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iMTIiIHZpZXdCb3g9IjAgMCAxMiAxMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTMgNEw2IDdMOSA0IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjEuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cjwvc3ZnPg==);
width: 12px;
height: 12px;
}
QComboBox QAbstractItemView {
background-color: #404040;
border: 1px solid #606060;
background-color: #3a3a3a;
border: 1px solid #555555;
selection-background-color: #0078d4;
color: #e0e0e0;
font-size: 14px;
color: #ffffff;
font-size: 12px;
}
""")
# 填充語言選項和連接信號
# 填充語言選項
self._populate_language_selector()
self.language_selector.currentIndexChanged.connect(self._on_language_changed)
language_row.addWidget(self.language_selector)
language_row.addStretch()
language_layout.addLayout(language_row)
lang_container.addWidget(self.language_selector)
lang_container.addStretch()
layout.addLayout(lang_container)
def _create_layout_section(self, layout: QVBoxLayout) -> None:
"""創建界面佈局區域"""
header = self._create_section_header(t('settings.layout.title'), "📐")
layout.addWidget(header)
# 保存引用以便更新
self.ui_elements['layout_header'] = header
# 語言說明
self.language_description_label = QLabel(t('settings.language.description'))
self.language_description_label.setStyleSheet("color: #9e9e9e; font-size: 12px; margin-top: 8px;")
self.language_description_label.setWordWrap(True)
language_layout.addWidget(self.language_description_label)
desc = self._create_description(t('settings.layout.description'))
layout.addWidget(desc)
# 保存引用以便更新
self.ui_elements['layout_desc'] = desc
layout.addWidget(self.language_group)
# 選項容器
options_layout = QVBoxLayout()
options_layout.setSpacing(2)
# === 界面佈局設置區域 ===
self.layout_group = QGroupBox(t('settings.layout.title'))
self.layout_group.setObjectName('layout_group')
layout_layout = QVBoxLayout(self.layout_group)
layout_layout.setSpacing(12)
layout_layout.setContentsMargins(16, 16, 16, 16)
# 佈局模式選擇 - 使用三個獨立的單選按鈕
# 創建按鈕組
self.layout_button_group = QButtonGroup()
# 分離模式
self.separate_mode_radio = QRadioButton(t('settings.layout.separateMode'))
self.separate_mode_radio.setChecked(not self.combined_mode)
self.separate_mode_radio.setStyleSheet("font-size: 14px; font-weight: bold; color: #e0e0e0;")
self.separate_mode_radio.setStyleSheet("""
QRadioButton {
font-family: "Microsoft JhengHei", "微軟正黑體", sans-serif;
font-size: 13px;
color: #ffffff;
spacing: 8px;
padding: 2px 0px;
}
QRadioButton::indicator {
width: 16px;
height: 16px;
}
QRadioButton::indicator:unchecked {
border: 2px solid #666666;
border-radius: 9px;
background-color: transparent;
}
QRadioButton::indicator:checked {
border: 2px solid #0078d4;
border-radius: 9px;
background-color: #0078d4;
image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOCIgaGVpZ2h0PSI4IiB2aWV3Qm94PSIwIDAgOCA4IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8Y2lyY2xlIGN4PSI0IiBjeT0iNCIgcj0iMiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+);
}
QRadioButton::indicator:hover {
border-color: #0078d4;
}
""")
self.layout_button_group.addButton(self.separate_mode_radio, 0)
layout_layout.addWidget(self.separate_mode_radio)
options_layout.addWidget(self.separate_mode_radio)
self.separate_desc_label = QLabel(t('settings.layout.separateModeDescription'))
self.separate_desc_label.setStyleSheet("color: #9e9e9e; font-size: 12px; margin-left: 20px; margin-bottom: 12px;")
self.separate_desc_label.setWordWrap(True)
layout_layout.addWidget(self.separate_desc_label)
separate_hint = QLabel(f" {t('settings.layout.separateModeDescription')}")
separate_hint.setStyleSheet("""
QLabel {
font-family: "Microsoft JhengHei", "微軟正黑體", sans-serif;
color: #888888;
font-size: 11px;
margin-left: 20px;
margin-bottom: 4px;
}
""")
options_layout.addWidget(separate_hint)
# 保存引用以便更新
self.ui_elements['separate_hint'] = separate_hint
# 合併模式(垂直布局)
# 合併模式(垂直
self.combined_vertical_radio = QRadioButton(t('settings.layout.combinedVertical'))
self.combined_vertical_radio.setChecked(self.combined_mode and self.layout_orientation == 'vertical')
self.combined_vertical_radio.setStyleSheet("font-size: 14px; font-weight: bold; color: #e0e0e0;")
self.combined_vertical_radio.setStyleSheet(self.separate_mode_radio.styleSheet())
self.layout_button_group.addButton(self.combined_vertical_radio, 1)
layout_layout.addWidget(self.combined_vertical_radio)
options_layout.addWidget(self.combined_vertical_radio)
self.combined_vertical_desc_label = QLabel(t('settings.layout.combinedVerticalDescription'))
self.combined_vertical_desc_label.setStyleSheet("color: #9e9e9e; font-size: 12px; margin-left: 20px; margin-bottom: 12px;")
self.combined_vertical_desc_label.setWordWrap(True)
layout_layout.addWidget(self.combined_vertical_desc_label)
vertical_hint = QLabel(f" {t('settings.layout.combinedVerticalDescription')}")
vertical_hint.setStyleSheet(separate_hint.styleSheet())
options_layout.addWidget(vertical_hint)
# 保存引用以便更新
self.ui_elements['vertical_hint'] = vertical_hint
# 合併模式(水平布局)
# 合併模式(水平
self.combined_horizontal_radio = QRadioButton(t('settings.layout.combinedHorizontal'))
self.combined_horizontal_radio.setChecked(self.combined_mode and self.layout_orientation == 'horizontal')
self.combined_horizontal_radio.setStyleSheet("font-size: 14px; font-weight: bold; color: #e0e0e0;")
self.combined_horizontal_radio.setStyleSheet(self.separate_mode_radio.styleSheet())
self.layout_button_group.addButton(self.combined_horizontal_radio, 2)
layout_layout.addWidget(self.combined_horizontal_radio)
options_layout.addWidget(self.combined_horizontal_radio)
self.combined_horizontal_desc_label = QLabel(t('settings.layout.combinedHorizontalDescription'))
self.combined_horizontal_desc_label.setStyleSheet("color: #9e9e9e; font-size: 12px; margin-left: 20px; margin-bottom: 12px;")
self.combined_horizontal_desc_label.setWordWrap(True)
layout_layout.addWidget(self.combined_horizontal_desc_label)
horizontal_hint = QLabel(f" {t('settings.layout.combinedHorizontalDescription')}")
horizontal_hint.setStyleSheet(separate_hint.styleSheet())
options_layout.addWidget(horizontal_hint)
# 保存引用以便更新
self.ui_elements['horizontal_hint'] = horizontal_hint
layout.addLayout(options_layout)
# 連接佈局變更信號
self.layout_button_group.buttonToggled.connect(self._on_layout_changed)
def _create_window_section(self, layout: QVBoxLayout) -> None:
"""創建視窗設置區域"""
header = self._create_section_header(t('settings.window.title'), "🖥️")
layout.addWidget(header)
# 保存引用以便更新
self.ui_elements['window_header'] = header
layout.addWidget(self.layout_group)
desc = self._create_description(t('settings.window.alwaysCenterDescription'))
layout.addWidget(desc)
# 保存引用以便更新
self.ui_elements['window_desc'] = desc
# === 視窗定位設置區域 ===
self.window_group = QGroupBox(t('settings.window.title'))
self.window_group.setObjectName('window_group')
window_layout = QVBoxLayout(self.window_group)
window_layout.setSpacing(12)
window_layout.setContentsMargins(16, 16, 16, 16)
# 選項容器
options_layout = QVBoxLayout()
options_layout.setSpacing(2)
# 總是在主螢幕中心顯示視窗選項
self.always_center_checkbox = QCheckBox(t('settings.window.alwaysCenter'))
self.always_center_checkbox.setChecked(self.config_manager.get_always_center_window())
self.always_center_checkbox.setStyleSheet("font-size: 14px; font-weight: bold; color: #e0e0e0;")
self.always_center_checkbox.setStyleSheet("""
QCheckBox {
font-family: "Microsoft JhengHei", "微軟正黑體", sans-serif;
font-size: 13px;
color: #ffffff;
spacing: 8px;
padding: 2px 0px;
}
QCheckBox::indicator {
width: 16px;
height: 16px;
}
QCheckBox::indicator:unchecked {
border: 2px solid #666666;
border-radius: 3px;
background-color: transparent;
}
QCheckBox::indicator:checked {
border: 2px solid #0078d4;
border-radius: 3px;
background-color: #0078d4;
image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iMTIiIHZpZXdCb3g9IjAgMCAxMiAxMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEwIDNMNC41IDguNUwyIDYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+);
}
QCheckBox::indicator:hover {
border-color: #0078d4;
}
""")
self.always_center_checkbox.stateChanged.connect(self._on_always_center_changed)
window_layout.addWidget(self.always_center_checkbox)
options_layout.addWidget(self.always_center_checkbox)
self.center_desc_label = QLabel(t('settings.window.alwaysCenterDescription'))
self.center_desc_label.setStyleSheet("color: #9e9e9e; font-size: 12px; margin-left: 20px; margin-bottom: 8px;")
self.center_desc_label.setWordWrap(True)
window_layout.addWidget(self.center_desc_label)
center_hint = QLabel(f" {t('settings.window.alwaysCenterDescription')}")
center_hint.setStyleSheet("""
QLabel {
font-family: "Microsoft JhengHei", "微軟正黑體", sans-serif;
color: #888888;
font-size: 11px;
margin-left: 20px;
margin-bottom: 4px;
}
""")
options_layout.addWidget(center_hint)
# 保存引用以便更新
self.ui_elements['center_hint'] = center_hint
layout.addWidget(self.window_group)
layout.addStretch()
layout.addLayout(options_layout)
def _create_reset_section(self, layout: QVBoxLayout) -> None:
"""創建重置設定區域"""
header = self._create_section_header(t('settings.reset.title'), "🔄")
layout.addWidget(header)
# 保存引用以便更新
self.ui_elements['reset_header'] = header
desc = self._create_description(t('settings.reset.description'))
layout.addWidget(desc)
# 保存引用以便更新
self.ui_elements['reset_desc'] = desc
reset_container = QHBoxLayout()
reset_container.setContentsMargins(0, 0, 0, 0)
self.reset_button = QPushButton(t('settings.reset.button'))
self.reset_button.setMinimumHeight(32)
self.reset_button.setMaximumWidth(110)
self.reset_button.setStyleSheet("""
QPushButton {
font-family: "Microsoft JhengHei", "微軟正黑體", sans-serif;
background-color: #dc3545;
color: white;
border: none;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
padding: 6px 12px;
}
QPushButton:hover {
background-color: #e55565;
}
QPushButton:pressed {
background-color: #c82333;
}
""")
self.reset_button.clicked.connect(self._on_reset_settings)
reset_container.addWidget(self.reset_button)
reset_container.addStretch()
layout.addLayout(reset_container)
def _populate_language_selector(self) -> None:
"""填充語言選擇器"""
# 保存當前選擇
current_lang = self.i18n.get_current_language()
languages = [
('zh-TW', '繁體中文'),
('zh-CN', '简体中文'),
('en', 'English')
]
# 暫時斷開信號連接,避免觸發語言變更事件
try:
self.language_selector.currentIndexChanged.disconnect()
except RuntimeError:
pass # 如果沒有連接則忽略
current_language = self.i18n.get_current_language()
# 清空並重新填充
# 暫時斷開信號連接以避免觸發變更事件
self.language_selector.blockSignals(True)
# 先清空現有選項
self.language_selector.clear()
for lang_code in self.i18n.get_supported_languages():
display_name = self.i18n.get_language_display_name(lang_code)
self.language_selector.addItem(display_name, lang_code)
# 設置當前選中的語言
for i in range(self.language_selector.count()):
if self.language_selector.itemData(i) == current_lang:
for i, (code, name) in enumerate(languages):
self.language_selector.addItem(name, code)
if code == current_language:
self.language_selector.setCurrentIndex(i)
break
# 重新連接信號
self.language_selector.currentIndexChanged.connect(self._on_language_changed)
self.language_selector.blockSignals(False)
def _on_language_changed(self, index: int) -> None:
"""處理語言變更"""
lang_code = self.language_selector.itemData(index)
if lang_code and self.i18n.set_language(lang_code):
# 發送語言變更信號
"""語言變更事件處理"""
if index < 0:
return
language_code = self.language_selector.itemData(index)
if language_code and language_code != self.i18n.get_current_language():
# 先保存語言設定
self.config_manager.set_language(language_code)
# 再設定語言
self.i18n.set_language(language_code)
# 發出信號
self.language_changed.emit()
def _on_layout_changed(self, button, checked: bool) -> None:
"""處理佈局變更"""
if not checked: # 只處理選中的按鈕
"""佈局變更事件處理"""
if not checked:
return
# 確定新的模式和方向
new_combined_mode = button == self.combined_vertical_radio or button == self.combined_horizontal_radio
new_orientation = 'vertical' if button == self.combined_vertical_radio else 'horizontal'
button_id = self.layout_button_group.id(button)
if button_id == 0: # 分離模式
new_combined_mode = False
new_orientation = 'vertical'
elif button_id == 1: # 合併模式(垂直)
new_combined_mode = True
new_orientation = 'vertical'
elif button_id == 2: # 合併模式(水平)
new_combined_mode = True
new_orientation = 'horizontal'
else:
return
# 檢查是否真的有變更
if new_combined_mode != self.combined_mode or new_orientation != self.layout_orientation:
# 提示用戶需要重新創建界面
reply = QMessageBox.question(
self,
t('app.layoutChangeTitle'),
t('app.layoutChangeMessage'),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.Yes
)
# 先保存配置
self.config_manager.set_layout_mode(new_combined_mode)
self.config_manager.set_layout_orientation(new_orientation)
if reply == QMessageBox.Yes:
# 用戶確認變更,發送佈局變更請求
self.combined_mode = new_combined_mode
self.layout_orientation = new_orientation
self.layout_change_requested.emit(self.combined_mode, self.layout_orientation)
else:
# 用戶選擇不重新載入,恢復原來的選項
if self.combined_mode:
if self.layout_orientation == 'vertical':
self.combined_vertical_radio.setChecked(True)
else:
self.combined_horizontal_radio.setChecked(True)
else:
self.separate_mode_radio.setChecked(True)
# 更新內部狀態
self.combined_mode = new_combined_mode
self.layout_orientation = new_orientation
# 發出佈局變更請求信號
self.layout_change_requested.emit(new_combined_mode, new_orientation)
def _on_always_center_changed(self, state: int) -> None:
"""處理視窗定位設置變更"""
always_center = state == 2 # Qt.Checked = 2
"""視窗定位選項變更事件處理"""
always_center = state == Qt.CheckState.Checked.value
# 立即保存設定
self.config_manager.set_always_center_window(always_center)
debug_log(f"視窗定位設置已保存: {always_center}") # 調試輸出
def _on_reset_settings(self) -> None:
"""重置設定事件處理"""
reply = QMessageBox.question(
self,
t('settings.reset.confirmTitle'),
t('settings.reset.confirmMessage'),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
if reply == QMessageBox.Yes:
self.reset_requested.emit()
def update_texts(self) -> None:
"""更新界面文字(用於語言切換)"""
# 更新GroupBox標題
self.language_group.setTitle(t('settings.language.title'))
self.layout_group.setTitle(t('settings.layout.title'))
self.window_group.setTitle(t('settings.window.title'))
"""更新界面文字(不重新創建界面)"""
# 更新區塊標題
if 'language_header' in self.ui_elements:
self.ui_elements['language_header'].setText(f"🌐 {t('settings.language.title')}")
if 'layout_header' in self.ui_elements:
self.ui_elements['layout_header'].setText(f"📐 {t('settings.layout.title')}")
if 'window_header' in self.ui_elements:
self.ui_elements['window_header'].setText(f"🖥️ {t('settings.window.title')}")
if 'reset_header' in self.ui_elements:
self.ui_elements['reset_header'].setText(f"🔄 {t('settings.reset.title')}")
# 更新標籤文字
self.language_label.setText(t('settings.language.selector'))
self.language_description_label.setText(t('settings.language.description'))
# 更新描述文字
if 'language_desc' in self.ui_elements:
self.ui_elements['language_desc'].setText(t('settings.language.description'))
if 'layout_desc' in self.ui_elements:
self.ui_elements['layout_desc'].setText(t('settings.layout.description'))
if 'window_desc' in self.ui_elements:
self.ui_elements['window_desc'].setText(t('settings.window.alwaysCenterDescription'))
if 'reset_desc' in self.ui_elements:
self.ui_elements['reset_desc'].setText(t('settings.reset.description'))
# 更新佈局設置文字
self.separate_mode_radio.setText(t('settings.layout.separateMode'))
self.combined_vertical_radio.setText(t('settings.layout.combinedVertical'))
self.combined_horizontal_radio.setText(t('settings.layout.combinedHorizontal'))
# 更新提示文字
if 'separate_hint' in self.ui_elements:
self.ui_elements['separate_hint'].setText(f" {t('settings.layout.separateModeDescription')}")
if 'vertical_hint' in self.ui_elements:
self.ui_elements['vertical_hint'].setText(f" {t('settings.layout.combinedVerticalDescription')}")
if 'horizontal_hint' in self.ui_elements:
self.ui_elements['horizontal_hint'].setText(f" {t('settings.layout.combinedHorizontalDescription')}")
if 'center_hint' in self.ui_elements:
self.ui_elements['center_hint'].setText(f" {t('settings.window.alwaysCenterDescription')}")
# 更新佈局描述文字
self.separate_desc_label.setText(t('settings.layout.separateModeDescription'))
self.combined_vertical_desc_label.setText(t('settings.layout.combinedVerticalDescription'))
self.combined_horizontal_desc_label.setText(t('settings.layout.combinedHorizontalDescription'))
# 更新按鈕文字
if hasattr(self, 'reset_button'):
self.reset_button.setText(t('settings.reset.button'))
# 更新視窗設置文字
self.always_center_checkbox.setText(t('settings.window.alwaysCenter'))
self.center_desc_label.setText(t('settings.window.alwaysCenterDescription'))
# 更新複選框文字
if hasattr(self, 'always_center_checkbox'):
self.always_center_checkbox.setText(t('settings.window.alwaysCenter'))
# 重新填充語言選擇器
self._populate_language_selector()
# 更新單選按鈕文字
if hasattr(self, 'separate_mode_radio'):
self.separate_mode_radio.setText(t('settings.layout.separateMode'))
if hasattr(self, 'combined_vertical_radio'):
self.combined_vertical_radio.setText(t('settings.layout.combinedVertical'))
if hasattr(self, 'combined_horizontal_radio'):
self.combined_horizontal_radio.setText(t('settings.layout.combinedHorizontal'))
# 重新設置勾選狀態,確保設置被正確保持
self.always_center_checkbox.setChecked(self.config_manager.get_always_center_window())
# 注意:不要重新填充語言選擇器,避免重複選項問題
def reload_settings_from_config(self) -> None:
"""從配置重新載入設定狀態"""
# 重新載入語言設定
if hasattr(self, 'language_selector'):
self._populate_language_selector()
# 重新載入佈局設定
self.combined_mode = self.config_manager.get_layout_mode()
self.layout_orientation = self.config_manager.get_layout_orientation()
self._set_initial_layout_state()
# 重新載入視窗設定
if hasattr(self, 'always_center_checkbox'):
always_center = self.config_manager.get_always_center_window()
self.always_center_checkbox.setChecked(always_center)
debug_log(f"重新載入視窗定位設置: {always_center}") # 調試輸出
def set_layout_mode(self, combined_mode: bool) -> None:
"""設置佈局模式"""
self.combined_mode = combined_mode
# 暫時斷開信號連接,避免觸發變更事件
try:
self.layout_button_group.buttonToggled.disconnect()
except RuntimeError:
pass
# 根據當前模式和方向設置正確的選項
if combined_mode:
if self.layout_orientation == 'vertical':
self.combined_vertical_radio.setChecked(True)
else: # horizontal
self.combined_horizontal_radio.setChecked(True)
else:
self.separate_mode_radio.setChecked(True)
# 重新連接信號
self.layout_button_group.buttonToggled.connect(self._on_layout_changed)
self._set_initial_layout_state()
def set_layout_orientation(self, orientation: str) -> None:
"""設置佈局方向"""
self.layout_orientation = orientation
# 暫時斷開信號連接,避免觸發變更事件
try:
self.layout_button_group.buttonToggled.disconnect()
except RuntimeError:
pass
# 如果是合併模式,根據方向設置正確的選項
if self.combined_mode:
if orientation == 'vertical':
self.combined_vertical_radio.setChecked(True)
else: # horizontal
self.combined_horizontal_radio.setChecked(True)
# 重新連接信號
self.layout_button_group.buttonToggled.connect(self._on_layout_changed)
self._set_initial_layout_state()
def _set_initial_layout_state(self) -> None:
"""設置初始佈局狀態"""
# 暫時斷開信號連接,避免觸發變更事件
try:
self.layout_button_group.buttonToggled.disconnect()
except RuntimeError:
pass
# 根據當前配置設置正確的選項
if self.combined_mode:
if self.layout_orientation == 'vertical':
if hasattr(self, 'separate_mode_radio'):
# 暫時斷開信號連接以避免觸發變更事件
self.layout_button_group.blockSignals(True)
if not self.combined_mode:
self.separate_mode_radio.setChecked(True)
elif self.layout_orientation == 'vertical':
self.combined_vertical_radio.setChecked(True)
else: # horizontal
else:
self.combined_horizontal_radio.setChecked(True)
else:
self.separate_mode_radio.setChecked(True)
# 重新連接信號
self.layout_button_group.buttonToggled.connect(self._on_layout_changed)
# 重新連接信號
self.layout_button_group.blockSignals(False)

View File

@ -120,4 +120,21 @@ class ConfigManager:
def set_always_center_window(self, always_center: bool) -> None:
"""設置總是在主螢幕中心顯示視窗"""
self.set('always_center_window', always_center)
debug_log(f"視窗定位設置: {'總是中心顯示' if always_center else '智能定位'}")
debug_log(f"視窗定位設置: {'總是中心顯示' if always_center else '智能定位'}")
def reset_settings(self) -> None:
"""重置所有設定到預設值"""
try:
# 清空配置緩存
self._config_cache = {}
# 刪除配置文件
if self._config_file.exists():
self._config_file.unlink()
debug_log("配置文件已刪除")
debug_log("所有設定已重置到預設值")
except Exception as e:
debug_log(f"重置設定失敗: {e}")
raise

View File

@ -34,6 +34,12 @@ class FeedbackWindow(QMainWindow):
# 初始化組件
self.config_manager = ConfigManager()
# 載入保存的語言設定
saved_language = self.config_manager.get_language()
if saved_language:
self.i18n.set_language(saved_language)
self.combined_mode = self.config_manager.get_layout_mode()
self.layout_orientation = self.config_manager.get_layout_orientation()
@ -348,6 +354,71 @@ class FeedbackWindow(QMainWindow):
if self.tab_manager.feedback_tab:
self.tab_manager.feedback_tab.handle_image_paste_from_textarea()
def _on_reset_settings_requested(self) -> None:
"""處理重置設定請求"""
try:
# 重置配置管理器的所有設定
self.config_manager.reset_settings()
# 重置應用程式狀態
self.combined_mode = False # 重置為分離模式
self.layout_orientation = 'vertical' # 重置為垂直布局
# 重新設置語言為預設
self.i18n.set_language('zh-TW')
# 保存當前內容
current_data = self.tab_manager.get_feedback_data()
# 重新創建分頁
self.tab_manager.set_layout_mode(self.combined_mode)
self.tab_manager.set_layout_orientation(self.layout_orientation)
self.tab_manager.create_tabs()
# 恢復內容
self.tab_manager.restore_content(
current_data["interactive_feedback"],
current_data["command_logs"],
current_data["images"]
)
# 重新連接信號
self.tab_manager.connect_signals(self)
# 重新載入設定分頁的狀態
if self.tab_manager.settings_tab:
self.tab_manager.settings_tab.reload_settings_from_config()
# 刷新UI文字
self._refresh_ui_texts()
# 重新應用視窗定位(使用重置後的設定)
self._apply_window_positioning()
# 切換到設定分頁顯示重置結果
settings_tab_index = 3 # 分離模式下設定分頁是第4個索引3
if settings_tab_index < self.tab_widget.count():
self.tab_widget.setCurrentIndex(settings_tab_index)
# 顯示成功訊息
QMessageBox.information(
self,
t('settings.reset.successTitle'),
t('settings.reset.successMessage'),
QMessageBox.Ok
)
debug_log("設定重置成功")
except Exception as e:
debug_log(f"重置設定失敗: {e}")
QMessageBox.critical(
self,
t('errors.title'),
t('settings.reset.error', error=str(e)),
QMessageBox.Ok
)
def _submit_feedback(self) -> None:
"""提交回饋"""
# 獲取所有回饋數據

View File

@ -312,10 +312,13 @@ class TabManager:
"""連接信號"""
# 連接設置分頁的信號
if self.settings_tab:
if hasattr(parent, 'language_changed'):
self.settings_tab.language_changed.connect(parent.language_changed)
# 語言變更信號直接連接到父窗口的刷新方法
if hasattr(parent, '_refresh_ui_texts'):
self.settings_tab.language_changed.connect(parent._refresh_ui_texts)
if hasattr(parent, '_on_layout_change_requested'):
self.settings_tab.layout_change_requested.connect(parent._on_layout_change_requested)
if hasattr(parent, '_on_reset_settings_requested'):
self.settings_tab.reset_requested.connect(parent._on_reset_settings_requested)
# 連接回饋分頁的圖片貼上信號
if self.feedback_tab:

View File

@ -92,6 +92,7 @@
},
"layout": {
"title": "Interface Layout",
"description": "Choose the display method for AI summary and feedback input areas",
"separateMode": "Separate Mode",
"separateModeDescription": "AI summary and feedback are in separate tabs",
"combinedVertical": "Combined Mode (Vertical Layout)",
@ -103,6 +104,17 @@
"title": "Window Positioning",
"alwaysCenter": "Always show window at primary screen center",
"alwaysCenterDescription": "Recommended for multi-monitor setups or when experiencing window positioning issues"
},
"reset": {
"title": "Reset Settings",
"description": "Clear all saved settings and restore to default state",
"button": "Reset Settings",
"confirmTitle": "Confirm Reset Settings",
"confirmMessage": "Are you sure you want to reset all settings? This will clear all saved preferences and restore to default state.",
"successTitle": "Reset Successful",
"successMessage": "All settings have been successfully reset to default values.",
"errorTitle": "Reset Failed",
"errorMessage": "Error occurred while resetting settings: {error}"
}
},
"buttons": {

View File

@ -72,6 +72,7 @@
},
"layout": {
"title": "界面布局",
"description": "选择 AI 摘要和反馈输入区域的显示方式",
"separateMode": "分离模式",
"separateModeDescription": "AI 摘要和反馈分别在不同页签",
"combinedVertical": "合并模式(垂直布局)",
@ -83,6 +84,17 @@
"title": "窗口定位",
"alwaysCenter": "总是在主屏幕中心显示窗口",
"alwaysCenterDescription": "建议在多屏幕环境或遇到窗口定位问题时开启此选项"
},
"reset": {
"title": "重置设置",
"description": "清除所有已保存的设置,恢复到默认状态",
"button": "重置设置",
"confirmTitle": "确认重置设置",
"confirmMessage": "确定要重置所有设置吗?这将清除所有已保存的偏好设置并恢复到默认状态。",
"successTitle": "重置成功",
"successMessage": "所有设置已成功重置为默认值。",
"errorTitle": "重置失败",
"errorMessage": "重置设置时发生错误:{error}"
}
},
"buttons": {

View File

@ -88,6 +88,7 @@
},
"layout": {
"title": "界面佈局",
"description": "選擇 AI 摘要和回饋輸入區域的顯示方式",
"separateMode": "分離模式",
"separateModeDescription": "AI 摘要和回饋分別在不同頁籤",
"combinedVertical": "合併模式(垂直布局)",
@ -99,6 +100,17 @@
"title": "視窗定位",
"alwaysCenter": "總是在主螢幕中心顯示視窗",
"alwaysCenterDescription": "建議在多螢幕環境或遇到視窗定位問題時開啟此選項"
},
"reset": {
"title": "重置設定",
"description": "清除所有已保存的設定,恢復到預設狀態",
"button": "重置設定",
"confirmTitle": "確認重置設定",
"confirmMessage": "確定要重置所有設定嗎?這將清除所有已保存的偏好設定並恢復到預設狀態。",
"successTitle": "重置成功",
"successMessage": "所有設定已成功重置為預設值。",
"errorTitle": "重置失敗",
"errorMessage": "重置設定時發生錯誤:{error}"
}
},
"buttons": {