feat: complete settings view + signatures + signatures DAO + icons
- SettingsView: complete UI with tabs for Accounts, Categories, Rules, Templates, Signatures, General, Appearance - Categories: QTreeWidget with hierarchical view, color picker, parent categories - Rules: QListWidget with RuleEditorDialog integration, toggle enabled - Templates: QListWidget with TemplateEditorDialog integration - Signatures: QListWidget with SignatureEditorDialog integration - SignatureDao: full CRUD with default signature support - common_structs.h: QColor for Category, all structs centralized - icons.qrc: updated with Linear/Outline/Bold icons from resources - Category: QColor instead of QString for color - EmailTreeModel/DateGroupProxyModel: email grouping by date - MailListView: QTreeView with date grouping combo - ReaderView: subject frame with shadow, avatar in header, body inside header - MainWindow: frameless with rounded corners, 1px border, edge resize, no status bar - icons.qrc: complete icon set from resources/icons/SVG
This commit is contained in:
+734
-27
@@ -1,6 +1,14 @@
|
||||
#include "ui/settingsview.h"
|
||||
#include "settingsview.h"
|
||||
#include "services/accountservice.h"
|
||||
#include "core/models/account.h"
|
||||
#include "db/dao/common_structs.h"
|
||||
#include "db/dao/categorydao.h"
|
||||
#include "db/dao/ruledao.h"
|
||||
#include "db/dao/templatedao.h"
|
||||
#include "db/dao/signaturedao.h"
|
||||
#include "ui/ruleditordialog.h"
|
||||
#include "ui/templateeditordialog.h"
|
||||
#include "ui/signaturemanagerdialog.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMessageBox>
|
||||
@@ -13,6 +21,19 @@
|
||||
#include <QButtonGroup>
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
#include <QRadioButton>
|
||||
#include <QTreeWidget>
|
||||
#include <QLineEdit>
|
||||
#include <QDialog>
|
||||
#include <QColorDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFormLayout>
|
||||
#include <QScrollArea>
|
||||
#include <QGroupBox>
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlDatabase>
|
||||
#include <QHeaderView>
|
||||
|
||||
SettingsView::SettingsView(QWidget *parent) : QWidget(parent) {
|
||||
setupUI();
|
||||
@@ -23,9 +44,13 @@ void SettingsView::setupUI() {
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
m_tabWidget = new QTabWidget();
|
||||
m_tabWidget->addTab(createAccountsTab(), "Accounts");
|
||||
m_tabWidget->addTab(createGeneralTab(), "General");
|
||||
m_tabWidget->addTab(createAppearanceTab(), "Appearance");
|
||||
m_tabWidget->addTab(createAccountsTab(), tr("Accounts"));
|
||||
m_tabWidget->addTab(createCategoriesTab(), tr("Categories"));
|
||||
m_tabWidget->addTab(createRulesTab(), tr("Rules"));
|
||||
m_tabWidget->addTab(createTemplatesTab(), tr("Templates"));
|
||||
m_tabWidget->addTab(createSignaturesTab(), tr("Signatures"));
|
||||
m_tabWidget->addTab(createGeneralTab(), tr("General"));
|
||||
m_tabWidget->addTab(createAppearanceTab(), tr("Appearance"));
|
||||
|
||||
mainLayout->addWidget(m_tabWidget);
|
||||
}
|
||||
@@ -35,9 +60,10 @@ QWidget* SettingsView::createAccountsTab() {
|
||||
QVBoxLayout *layout = new QVBoxLayout(widget);
|
||||
layout->setContentsMargins(20, 20, 20, 20);
|
||||
|
||||
QLabel *title = new QLabel("Email Accounts");
|
||||
QLabel *title = new QLabel(tr("Email Accounts"));
|
||||
QFont titleFont = title->font();
|
||||
titleFont.setPointSize(16);
|
||||
titleFont.setBold(true);
|
||||
title->setFont(titleFont);
|
||||
layout->addWidget(title);
|
||||
|
||||
@@ -51,21 +77,22 @@ QWidget* SettingsView::createAccountsTab() {
|
||||
layout->addWidget(m_accountList);
|
||||
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout();
|
||||
m_addBtn = new QPushButton("Add Account");
|
||||
m_addBtn = new QPushButton(tr("Add Account"));
|
||||
m_addBtn->setStyleSheet(
|
||||
"QPushButton { background: #FFEB3B; color: white; border: none; border-radius: 4px; "
|
||||
"QPushButton { background: #1976D2; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #FDD835; }"
|
||||
"QPushButton:hover { background: #1565C0; }"
|
||||
);
|
||||
buttonLayout->addWidget(m_addBtn);
|
||||
m_editBtn = new QPushButton("Edit");
|
||||
|
||||
m_editBtn = new QPushButton(tr("Edit"));
|
||||
m_editBtn->setEnabled(false);
|
||||
m_editBtn->setStyleSheet(
|
||||
"QPushButton { background: #FFA726; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #FB8C00; }"
|
||||
);
|
||||
m_deleteBtn = new QPushButton("Delete");
|
||||
m_deleteBtn = new QPushButton(tr("Delete"));
|
||||
m_deleteBtn->setEnabled(false);
|
||||
m_deleteBtn->setStyleSheet(
|
||||
"QPushButton { background: #EF5350; color: white; border: none; border-radius: 4px; "
|
||||
@@ -85,32 +112,283 @@ QWidget* SettingsView::createAccountsTab() {
|
||||
return widget;
|
||||
}
|
||||
|
||||
QWidget* SettingsView::createCategoriesTab() {
|
||||
QWidget *widget = new QWidget();
|
||||
QVBoxLayout *layout = new QVBoxLayout(widget);
|
||||
layout->setContentsMargins(12, 12, 12, 12);
|
||||
layout->setSpacing(8);
|
||||
|
||||
QLabel *title = new QLabel(tr("Categories"));
|
||||
QFont titleFont = title->font();
|
||||
titleFont.setPointSize(16);
|
||||
titleFont.setBold(true);
|
||||
title->setFont(titleFont);
|
||||
layout->addWidget(title);
|
||||
|
||||
m_categoryTree = new QTreeWidget();
|
||||
m_categoryTree->setHeaderLabels({tr("Category"), tr("Color"), tr("Account")});
|
||||
m_categoryTree->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_categoryTree->setRootIsDecorated(true);
|
||||
m_categoryTree->setItemsExpandable(true);
|
||||
m_categoryTree->setStyleSheet(
|
||||
"QTreeWidget { background: #ffffff; border: 1px solid #e0e0e0; border-radius: 4px; }"
|
||||
"QTreeWidget::item { padding: 8px; border-bottom: 1px solid #f0f0f0; }"
|
||||
"QTreeWidget::item:selected { background: #e3f2fd; }"
|
||||
);
|
||||
m_categoryTree->setColumnWidth(0, 250);
|
||||
m_categoryTree->setColumnWidth(1, 80);
|
||||
m_categoryTree->header()->setStretchLastSection(false);
|
||||
layout->addWidget(m_categoryTree);
|
||||
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout();
|
||||
m_categoryAddBtn = new QPushButton(tr("New Category"));
|
||||
m_categoryAddBtn->setStyleSheet(
|
||||
"QPushButton { background: #1976D2; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #1565C0; }"
|
||||
);
|
||||
m_categoryEditBtn = new QPushButton(tr("Edit"));
|
||||
m_categoryEditBtn->setEnabled(false);
|
||||
m_categoryEditBtn->setStyleSheet(
|
||||
"QPushButton { background: #FFA726; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #FB8C00; }"
|
||||
);
|
||||
m_categoryDeleteBtn = new QPushButton(tr("Delete"));
|
||||
m_categoryDeleteBtn->setEnabled(false);
|
||||
m_categoryDeleteBtn->setStyleSheet(
|
||||
"QPushButton { background: #EF5350; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #E53935; }"
|
||||
);
|
||||
|
||||
buttonLayout->addWidget(m_categoryAddBtn);
|
||||
buttonLayout->addWidget(m_categoryEditBtn);
|
||||
buttonLayout->addWidget(m_categoryDeleteBtn);
|
||||
buttonLayout->addStretch();
|
||||
layout->addLayout(buttonLayout);
|
||||
|
||||
connect(m_categoryTree, &QTreeWidget::itemSelectionChanged, this, &SettingsView::onCategorySelectionChanged);
|
||||
connect(m_categoryAddBtn, &QPushButton::clicked, this, &SettingsView::onCategoryAddClicked);
|
||||
connect(m_categoryEditBtn, &QPushButton::clicked, this, &SettingsView::onCategoryEditClicked);
|
||||
connect(m_categoryDeleteBtn, &QPushButton::clicked, this, &SettingsView::onCategoryDeleteClicked);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
QWidget* SettingsView::createRulesTab() {
|
||||
QWidget *widget = new QWidget();
|
||||
QVBoxLayout *layout = new QVBoxLayout(widget);
|
||||
layout->setContentsMargins(12, 12, 12, 12);
|
||||
layout->setSpacing(8);
|
||||
|
||||
QLabel *title = new QLabel(tr("Rules"));
|
||||
QFont titleFont = title->font();
|
||||
titleFont.setPointSize(16);
|
||||
titleFont.setBold(true);
|
||||
title->setFont(titleFont);
|
||||
layout->addWidget(title);
|
||||
|
||||
m_ruleList = new QListWidget();
|
||||
m_ruleList->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_ruleList->setStyleSheet(
|
||||
"QListWidget { background: #ffffff; border: 1px solid #e0e0e0; border-radius: 4px; }"
|
||||
"QListWidget::item { padding: 12px; border-bottom: 1px solid #f0f0f0; }"
|
||||
"QListWidget::item:selected { background: #e3f2fd; }"
|
||||
);
|
||||
m_ruleList->setSpacing(2);
|
||||
layout->addWidget(m_ruleList);
|
||||
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout();
|
||||
m_ruleAddBtn = new QPushButton(tr("New Rule"));
|
||||
m_ruleAddBtn->setStyleSheet(
|
||||
"QPushButton { background: #1976D2; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #1565C0; }"
|
||||
);
|
||||
m_ruleEditBtn = new QPushButton(tr("Edit"));
|
||||
m_ruleEditBtn->setEnabled(false);
|
||||
m_ruleEditBtn->setStyleSheet(
|
||||
"QPushButton { background: #FFA726; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #FB8C00; }"
|
||||
);
|
||||
m_ruleDeleteBtn = new QPushButton(tr("Delete"));
|
||||
m_ruleDeleteBtn->setEnabled(false);
|
||||
m_ruleDeleteBtn->setStyleSheet(
|
||||
"QPushButton { background: #EF5350; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #E53935; }"
|
||||
);
|
||||
m_ruleToggleBtn = new QPushButton(tr("Toggle"));
|
||||
m_ruleToggleBtn->setEnabled(false);
|
||||
m_ruleToggleBtn->setStyleSheet(
|
||||
"QPushButton { background: #66BB6A; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #4CAF50; }"
|
||||
);
|
||||
|
||||
buttonLayout->addWidget(m_ruleAddBtn);
|
||||
buttonLayout->addWidget(m_ruleEditBtn);
|
||||
buttonLayout->addWidget(m_ruleDeleteBtn);
|
||||
buttonLayout->addWidget(m_ruleToggleBtn);
|
||||
buttonLayout->addStretch();
|
||||
layout->addLayout(buttonLayout);
|
||||
|
||||
connect(m_ruleList, &QListWidget::itemSelectionChanged, this, &SettingsView::onRuleSelectionChanged);
|
||||
connect(m_ruleAddBtn, &QPushButton::clicked, this, &SettingsView::onRuleAddClicked);
|
||||
connect(m_ruleEditBtn, &QPushButton::clicked, this, &SettingsView::onRuleEditClicked);
|
||||
connect(m_ruleDeleteBtn, &QPushButton::clicked, this, &SettingsView::onRuleDeleteClicked);
|
||||
connect(m_ruleToggleBtn, &QPushButton::clicked, this, &SettingsView::onRuleToggleEnabled);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
QWidget* SettingsView::createTemplatesTab() {
|
||||
QWidget *widget = new QWidget();
|
||||
QVBoxLayout *layout = new QVBoxLayout(widget);
|
||||
layout->setContentsMargins(12, 12, 12, 12);
|
||||
layout->setSpacing(8);
|
||||
|
||||
QLabel *title = new QLabel(tr("Templates"));
|
||||
QFont titleFont = title->font();
|
||||
titleFont.setPointSize(16);
|
||||
titleFont.setBold(true);
|
||||
title->setFont(titleFont);
|
||||
layout->addWidget(title);
|
||||
|
||||
m_templateList = new QListWidget();
|
||||
m_templateList->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_templateList->setStyleSheet(
|
||||
"QListWidget { background: #ffffff; border: 1px solid #e0e0e0; border-radius: 4px; }"
|
||||
"QListWidget::item { padding: 12px; border-bottom: 1px solid #f0f0f0; }"
|
||||
"QListWidget::item:selected { background: #e3f2fd; }"
|
||||
);
|
||||
m_templateList->setSpacing(2);
|
||||
layout->addWidget(m_templateList);
|
||||
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout();
|
||||
m_templateAddBtn = new QPushButton(tr("New Template"));
|
||||
m_templateAddBtn->setStyleSheet(
|
||||
"QPushButton { background: #1976D2; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #1565C0; }"
|
||||
);
|
||||
m_templateEditBtn = new QPushButton(tr("Edit"));
|
||||
m_templateEditBtn->setEnabled(false);
|
||||
m_templateEditBtn->setStyleSheet(
|
||||
"QPushButton { background: #FFA726; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #FB8C00; }"
|
||||
);
|
||||
m_templateDeleteBtn = new QPushButton(tr("Delete"));
|
||||
m_templateDeleteBtn->setEnabled(false);
|
||||
m_templateDeleteBtn->setStyleSheet(
|
||||
"QPushButton { background: #EF5350; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #E53935; }"
|
||||
);
|
||||
|
||||
buttonLayout->addWidget(m_templateAddBtn);
|
||||
buttonLayout->addWidget(m_templateEditBtn);
|
||||
buttonLayout->addWidget(m_templateDeleteBtn);
|
||||
buttonLayout->addStretch();
|
||||
layout->addLayout(buttonLayout);
|
||||
|
||||
connect(m_templateList, &QListWidget::itemSelectionChanged, this, &SettingsView::onTemplateSelectionChanged);
|
||||
connect(m_templateAddBtn, &QPushButton::clicked, this, &SettingsView::onTemplateAddClicked);
|
||||
connect(m_templateEditBtn, &QPushButton::clicked, this, &SettingsView::onTemplateEditClicked);
|
||||
connect(m_templateDeleteBtn, &QPushButton::clicked, this, &SettingsView::onTemplateDeleteClicked);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
QWidget* SettingsView::createSignaturesTab() {
|
||||
QWidget *widget = new QWidget();
|
||||
QVBoxLayout *layout = new QVBoxLayout(widget);
|
||||
layout->setContentsMargins(12, 12, 12, 12);
|
||||
layout->setSpacing(8);
|
||||
|
||||
QLabel *title = new QLabel(tr("Signatures"));
|
||||
QFont titleFont = title->font();
|
||||
titleFont.setPointSize(16);
|
||||
titleFont.setBold(true);
|
||||
title->setFont(titleFont);
|
||||
layout->addWidget(title);
|
||||
|
||||
m_signatureList = new QListWidget();
|
||||
m_signatureList->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_signatureList->setStyleSheet(
|
||||
"QListWidget { background: #ffffff; border: 1px solid #e0e0e0; border-radius: 4px; }"
|
||||
"QListWidget::item { padding: 12px; border-bottom: 1px solid #f0f0f0; }"
|
||||
"QListWidget::item:selected { background: #e3f2fd; }"
|
||||
);
|
||||
m_signatureList->setSpacing(2);
|
||||
layout->addWidget(m_signatureList);
|
||||
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout();
|
||||
m_signatureAddBtn = new QPushButton(tr("New Signature"));
|
||||
m_signatureAddBtn->setStyleSheet(
|
||||
"QPushButton { background: #1976D2; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #1565C0; }"
|
||||
);
|
||||
m_signatureEditBtn = new QPushButton(tr("Edit"));
|
||||
m_signatureEditBtn->setEnabled(false);
|
||||
m_signatureEditBtn->setStyleSheet(
|
||||
"QPushButton { background: #FFA726; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #FB8C00; }"
|
||||
);
|
||||
m_signatureDeleteBtn = new QPushButton(tr("Delete"));
|
||||
m_signatureDeleteBtn->setEnabled(false);
|
||||
m_signatureDeleteBtn->setStyleSheet(
|
||||
"QPushButton { background: #EF5350; color: white; border: none; border-radius: 4px; "
|
||||
"padding: 8px 16px; font-weight: bold; }"
|
||||
"QPushButton:hover { background: #E53935; }"
|
||||
);
|
||||
|
||||
buttonLayout->addWidget(m_signatureAddBtn);
|
||||
buttonLayout->addWidget(m_signatureEditBtn);
|
||||
buttonLayout->addWidget(m_signatureDeleteBtn);
|
||||
buttonLayout->addStretch();
|
||||
layout->addLayout(buttonLayout);
|
||||
|
||||
connect(m_signatureList, &QListWidget::itemSelectionChanged, this, &SettingsView::onSignatureSelectionChanged);
|
||||
connect(m_signatureAddBtn, &QPushButton::clicked, this, &SettingsView::onSignatureAddClicked);
|
||||
connect(m_signatureEditBtn, &QPushButton::clicked, this, &SettingsView::onSignatureEditClicked);
|
||||
connect(m_signatureDeleteBtn, &QPushButton::clicked, this, &SettingsView::onSignatureDeleteClicked);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
QWidget* SettingsView::createGeneralTab() {
|
||||
QWidget *widget = new QWidget();
|
||||
QVBoxLayout *layout = new QVBoxLayout(widget);
|
||||
layout->setContentsMargins(20, 20, 20, 20);
|
||||
|
||||
QLabel *title = new QLabel("General Settings");
|
||||
QLabel *title = new QLabel(tr("General Settings"));
|
||||
QFont titleFont = title->font();
|
||||
titleFont.setPointSize(16);
|
||||
titleFont.setBold(true);
|
||||
title->setFont(titleFont);
|
||||
layout->addWidget(title);
|
||||
|
||||
QCheckBox *startOnLogin = new QCheckBox("Start application on login");
|
||||
QCheckBox *startOnLogin = new QCheckBox(tr("Start application on login"));
|
||||
startOnLogin->setChecked(true);
|
||||
connect(startOnLogin, &QCheckBox::toggled, this, [this](bool checked) {
|
||||
emit settingChanged("start_on_login", QVariant(checked));
|
||||
});
|
||||
layout->addWidget(startOnLogin);
|
||||
|
||||
QCheckBox *enableNotifications = new QCheckBox("Enable notifications");
|
||||
QCheckBox *enableNotifications = new QCheckBox(tr("Enable notifications"));
|
||||
enableNotifications->setChecked(true);
|
||||
connect(enableNotifications, &QCheckBox::toggled, this, [this](bool checked) {
|
||||
emit settingChanged("enable_notifications", QVariant(checked));
|
||||
});
|
||||
layout->addWidget(enableNotifications);
|
||||
|
||||
QCheckBox *minimizeToTray = new QCheckBox("Minimize to tray on close");
|
||||
QCheckBox *minimizeToTray = new QCheckBox(tr("Minimize to tray on close"));
|
||||
minimizeToTray->setChecked(true);
|
||||
connect(minimizeToTray, &QCheckBox::toggled, this, [this](bool checked) {
|
||||
emit settingChanged("minimize_to_tray", QVariant(checked));
|
||||
@@ -126,22 +404,23 @@ QWidget* SettingsView::createAppearanceTab() {
|
||||
QVBoxLayout *layout = new QVBoxLayout(widget);
|
||||
layout->setContentsMargins(20, 20, 20, 20);
|
||||
|
||||
QLabel *title = new QLabel("Appearance");
|
||||
QLabel *title = new QLabel(tr("Appearance"));
|
||||
QFont titleFont = title->font();
|
||||
titleFont.setPointSize(16);
|
||||
titleFont.setBold(true);
|
||||
title->setFont(titleFont);
|
||||
layout->addWidget(title);
|
||||
|
||||
QLabel *themeLabel = new QLabel("Theme");
|
||||
QLabel *themeLabel = new QLabel(tr("Theme"));
|
||||
QFont labelFont = themeLabel->font();
|
||||
labelFont.setBold(true);
|
||||
themeLabel->setFont(labelFont);
|
||||
layout->addWidget(themeLabel);
|
||||
|
||||
m_themeGroup = new QButtonGroup(this);
|
||||
QRadioButton *lightRadio = new QRadioButton("Light");
|
||||
QRadioButton *darkRadio = new QRadioButton("Dark");
|
||||
QRadioButton *systemRadio = new QRadioButton("System");
|
||||
QRadioButton *lightRadio = new QRadioButton(tr("Light"));
|
||||
QRadioButton *darkRadio = new QRadioButton(tr("Dark"));
|
||||
QRadioButton *systemRadio = new QRadioButton(tr("System"));
|
||||
m_themeGroup->addButton(lightRadio, 0);
|
||||
m_themeGroup->addButton(darkRadio, 1);
|
||||
m_themeGroup->addButton(systemRadio, 2);
|
||||
@@ -155,14 +434,14 @@ QWidget* SettingsView::createAppearanceTab() {
|
||||
connect(m_themeGroup, QOverload<int>::of(&QButtonGroup::idClicked), this, [this](int id) {
|
||||
QString theme;
|
||||
switch (id) {
|
||||
case 0: theme = "light"; break;
|
||||
case 1: theme = "dark"; break;
|
||||
case 2: theme = "system"; break;
|
||||
case 0: theme = "light"; break;
|
||||
case 1: theme = "dark"; break;
|
||||
case 2: theme = "system"; break;
|
||||
}
|
||||
emit themeChanged(theme);
|
||||
});
|
||||
|
||||
QCheckBox *deepinTheme = new QCheckBox("Deepin theme (experimental)");
|
||||
QCheckBox *deepinTheme = new QCheckBox(tr("Deepin theme (experimental)"));
|
||||
deepinTheme->setChecked(true);
|
||||
connect(deepinTheme, &QCheckBox::toggled, this, [this](bool checked) {
|
||||
emit settingChanged("deepin_theme", QVariant(checked));
|
||||
@@ -173,6 +452,7 @@ QWidget* SettingsView::createAppearanceTab() {
|
||||
return widget;
|
||||
}
|
||||
|
||||
// ========== Slots for Accounts ==========
|
||||
void SettingsView::setAccountService(AccountService *service) {
|
||||
m_accountService = service;
|
||||
if (m_accountService) {
|
||||
@@ -204,8 +484,8 @@ void SettingsView::loadAccounts() {
|
||||
m_accountList->setCurrentRow(0);
|
||||
}
|
||||
}
|
||||
void SettingsView::onAccountSelectionChanged()
|
||||
{
|
||||
|
||||
void SettingsView::onAccountSelectionChanged() {
|
||||
QList<QListWidgetItem*> items = m_accountList->selectedItems();
|
||||
qDebug() << "SettingsView::onAccountSelectionChanged, selected items count:" << items.size();
|
||||
if (items.isEmpty()) {
|
||||
@@ -231,10 +511,10 @@ void SettingsView::onEditClicked() {
|
||||
void SettingsView::onDeleteClicked() {
|
||||
if (m_selectedAccountId != -1 && m_accountService) {
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setWindowTitle("Delete Account");
|
||||
msgBox.setWindowTitle(tr("Delete Account"));
|
||||
Account* account = m_accountService->findAccountById(m_selectedAccountId);
|
||||
QString accountName = account ? account->email() : QString::number(m_selectedAccountId);
|
||||
msgBox.setText(QString("Are you sure you want to delete the account \"%1\"?").arg(accountName));
|
||||
msgBox.setText(tr("Are you sure you want to delete the account \"%1\"?").arg(accountName));
|
||||
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
msgBox.setDefaultButton(QMessageBox::No);
|
||||
if (msgBox.exec() == QMessageBox::Yes) {
|
||||
@@ -242,3 +522,430 @@ void SettingsView::onDeleteClicked() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========== Category Slots ==========
|
||||
void SettingsView::onCategorySelectionChanged() {
|
||||
bool hasSelection = !m_categoryTree->selectedItems().isEmpty();
|
||||
m_categoryEditBtn->setEnabled(hasSelection);
|
||||
m_categoryDeleteBtn->setEnabled(hasSelection);
|
||||
}
|
||||
|
||||
void SettingsView::onCategoryAddClicked() {
|
||||
QDialog dlg(this);
|
||||
dlg.setWindowTitle(tr("New Category"));
|
||||
dlg.setMinimumWidth(400);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(&dlg);
|
||||
QFormLayout *form = new QFormLayout();
|
||||
|
||||
QLineEdit *nameEdit = new QLineEdit();
|
||||
form->addRow(tr("Name:"), nameEdit);
|
||||
|
||||
QPushButton *colorBtn = new QPushButton();
|
||||
colorBtn->setFixedSize(24, 24);
|
||||
QColor catColor = QColor("#1976D2");
|
||||
colorBtn->setStyleSheet(QString("background-color: %1; border: 1px solid #ccc; border-radius: 4px;").arg(catColor.name()));
|
||||
connect(colorBtn, &QPushButton::clicked, [&catColor, colorBtn]() {
|
||||
QColor c = QColorDialog::getColor(catColor);
|
||||
if (c.isValid()) {
|
||||
catColor = c;
|
||||
colorBtn->setStyleSheet(QString("background-color: %1; border: 1px solid #ccc; border-radius: 4px;").arg(c.name()));
|
||||
}
|
||||
});
|
||||
|
||||
QHBoxLayout *colorLayout = new QHBoxLayout();
|
||||
colorLayout->addWidget(colorBtn);
|
||||
colorLayout->addStretch();
|
||||
form->addRow(tr("Color:"), colorLayout);
|
||||
|
||||
QComboBox *parentCombo = new QComboBox();
|
||||
parentCombo->addItem(tr("(None - Top Level)"), QVariant());
|
||||
form->addRow(tr("Parent:"), parentCombo);
|
||||
|
||||
layout->addLayout(form);
|
||||
|
||||
QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
connect(buttons, &QDialogButtonBox::accepted, &dlg, &QDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, &dlg, &QDialog::reject);
|
||||
layout->addWidget(buttons);
|
||||
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
Category cat;
|
||||
cat.name = nameEdit->text().trimmed();
|
||||
cat.color = catColor;
|
||||
cat.accountId = -1; // Global by default
|
||||
cat.parentCategoryId = parentCombo->currentData().toLongLong();
|
||||
if (!cat.name.isEmpty()) {
|
||||
emit categoryAddRequested(cat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsView::onCategoryEditClicked() {
|
||||
QTreeWidgetItem *item = m_categoryTree->currentItem();
|
||||
if (!item) return;
|
||||
|
||||
qint64 catId = item->data(0, Qt::UserRole).toLongLong();
|
||||
std::optional<Category> catOpt = CategoryDao::findById(catId);
|
||||
if (!catOpt.has_value()) return;
|
||||
Category cat = *catOpt;
|
||||
|
||||
QDialog dlg(this);
|
||||
dlg.setWindowTitle(tr("Edit Category"));
|
||||
dlg.setMinimumWidth(400);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(&dlg);
|
||||
QFormLayout *form = new QFormLayout();
|
||||
|
||||
QLineEdit *nameEdit = new QLineEdit(cat.name);
|
||||
form->addRow(tr("Name:"), nameEdit);
|
||||
|
||||
QPushButton *colorBtn = new QPushButton();
|
||||
colorBtn->setFixedSize(24, 24);
|
||||
colorBtn->setStyleSheet(QString("background-color: %1; border: 1px solid #ccc; border-radius: 4px;").arg(cat.color.name()));
|
||||
QColor catColor = cat.color;
|
||||
connect(colorBtn, &QPushButton::clicked, [&catColor, colorBtn]() {
|
||||
QColor c = QColorDialog::getColor(catColor);
|
||||
if (c.isValid()) {
|
||||
catColor = c;
|
||||
colorBtn->setStyleSheet(QString("background-color: %1; border: 1px solid #ccc; border-radius: 4px;").arg(c.name()));
|
||||
}
|
||||
});
|
||||
|
||||
QHBoxLayout *colorLayout = new QHBoxLayout();
|
||||
colorLayout->addWidget(colorBtn);
|
||||
colorLayout->addStretch();
|
||||
form->addRow(tr("Color:"), colorLayout);
|
||||
|
||||
layout->addLayout(form);
|
||||
|
||||
QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
connect(buttons, &QDialogButtonBox::accepted, &dlg, &QDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, &dlg, &QDialog::reject);
|
||||
layout->addWidget(buttons);
|
||||
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
cat.name = nameEdit->text().trimmed();
|
||||
cat.color = catColor;
|
||||
if (!cat.name.isEmpty()) {
|
||||
emit categoryEditRequested(cat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsView::onCategoryDeleteClicked() {
|
||||
QTreeWidgetItem *item = m_categoryTree->currentItem();
|
||||
if (!item) return;
|
||||
|
||||
qint64 catId = item->data(0, Qt::UserRole).toLongLong();
|
||||
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setWindowTitle(tr("Delete Category"));
|
||||
msgBox.setText(tr("Are you sure you want to delete this category?"));
|
||||
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
msgBox.setDefaultButton(QMessageBox::No);
|
||||
if (msgBox.exec() == QMessageBox::Yes) {
|
||||
emit categoryDeleteRequested(catId);
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsView::loadCategories() {
|
||||
refreshCategoryTree();
|
||||
}
|
||||
|
||||
void SettingsView::refreshCategoryTree() {
|
||||
m_categoryTree->clear();
|
||||
|
||||
// Load global categories
|
||||
QVector<Category> globalCats = CategoryDao::findGlobal();
|
||||
for (const Category &cat : globalCats) {
|
||||
QTreeWidgetItem *item = createCategoryTreeItem(cat);
|
||||
m_categoryTree->addTopLevelItem(item);
|
||||
}
|
||||
|
||||
// Load account-specific categories for selected account
|
||||
if (m_selectedAccountId > 0) {
|
||||
QVector<Category> accountCats = CategoryDao::findByAccount(m_selectedAccountId);
|
||||
for (const Category &cat : accountCats) {
|
||||
QTreeWidgetItem *item = createCategoryTreeItem(cat);
|
||||
m_categoryTree->addTopLevelItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
m_categoryTree->expandAll();
|
||||
}
|
||||
|
||||
QTreeWidgetItem* SettingsView::createCategoryTreeItem(const Category &cat, QTreeWidgetItem *parent) {
|
||||
QTreeWidgetItem *item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem();
|
||||
|
||||
item->setText(0, cat.name);
|
||||
item->setData(0, Qt::UserRole, cat.id);
|
||||
|
||||
// Color indicator
|
||||
QTableWidgetItem *colorItem = new QTableWidgetItem();
|
||||
colorItem->setBackground(cat.color);
|
||||
colorItem->setFlags(colorItem->flags() & ~Qt::ItemIsEditable);
|
||||
|
||||
// Account info
|
||||
QString accountInfo = cat.accountId >= 0 ? QString("Account %1").arg(cat.accountId) : tr("Global");
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
// ========== Rule Slots ==========
|
||||
void SettingsView::onRuleSelectionChanged() {
|
||||
bool hasSelection = m_ruleList->currentRow() >= 0;
|
||||
m_ruleEditBtn->setEnabled(hasSelection);
|
||||
m_ruleDeleteBtn->setEnabled(hasSelection);
|
||||
m_ruleToggleBtn->setEnabled(hasSelection);
|
||||
}
|
||||
|
||||
void SettingsView::onRuleAddClicked() {
|
||||
RuleEditorDialog dlg(Rule(), -1, this);
|
||||
connect(&dlg, &RuleEditorDialog::ruleSaved, this, [this](const Rule& rule) {
|
||||
emit ruleAddRequested(rule);
|
||||
});
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void SettingsView::onRuleEditClicked() {
|
||||
int row = m_ruleList->currentRow();
|
||||
if (row < 0) return;
|
||||
|
||||
QListWidgetItem *item = m_ruleList->item(row);
|
||||
qint64 ruleId = item->data(Qt::UserRole).toLongLong();
|
||||
std::optional<Rule> ruleOpt = RuleDao::findById(ruleId);
|
||||
if (!ruleOpt.has_value()) return;
|
||||
|
||||
RuleEditorDialog dlg(*ruleOpt, -1, this);
|
||||
connect(&dlg, &RuleEditorDialog::ruleSaved, this, [this](const Rule& rule) {
|
||||
emit ruleEditRequested(rule);
|
||||
});
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void SettingsView::onRuleDeleteClicked() {
|
||||
int row = m_ruleList->currentRow();
|
||||
if (row < 0) return;
|
||||
|
||||
QListWidgetItem *item = m_ruleList->item(row);
|
||||
qint64 ruleId = item->data(Qt::UserRole).toLongLong();
|
||||
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setWindowTitle(tr("Delete Rule"));
|
||||
msgBox.setText(tr("Are you sure you want to delete this rule?"));
|
||||
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
msgBox.setDefaultButton(QMessageBox::No);
|
||||
if (msgBox.exec() == QMessageBox::Yes) {
|
||||
emit ruleDeleteRequested(ruleId);
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsView::onRuleToggleEnabled() {
|
||||
int row = m_ruleList->currentRow();
|
||||
if (row < 0) return;
|
||||
|
||||
QListWidgetItem *item = m_ruleList->item(row);
|
||||
qint64 ruleId = item->data(Qt::UserRole).toLongLong();
|
||||
std::optional<Rule> ruleOpt = RuleDao::findById(ruleId);
|
||||
if (!ruleOpt.has_value()) return;
|
||||
|
||||
Rule rule = *ruleOpt;
|
||||
rule.enabled = !rule.enabled;
|
||||
emit ruleEditRequested(rule);
|
||||
}
|
||||
|
||||
void SettingsView::loadRules() {
|
||||
m_ruleList->clear();
|
||||
|
||||
// Load global rules
|
||||
QVector<Rule> globalRules = RuleDao::findGlobal();
|
||||
for (const Rule &rule : globalRules) {
|
||||
QListWidgetItem *item = new QListWidgetItem(ruleToString(rule));
|
||||
item->setData(Qt::UserRole, rule.id);
|
||||
if (!rule.enabled) {
|
||||
item->setForeground(Qt::gray);
|
||||
}
|
||||
m_ruleList->addItem(item);
|
||||
}
|
||||
|
||||
// Load account-specific rules for selected account
|
||||
if (m_selectedAccountId > 0) {
|
||||
QVector<Rule> accountRules = RuleDao::findByAccount(m_selectedAccountId);
|
||||
for (const Rule &rule : accountRules) {
|
||||
QListWidgetItem *item = new QListWidgetItem(ruleToString(rule));
|
||||
item->setData(Qt::UserRole, rule.id);
|
||||
if (!rule.enabled) {
|
||||
item->setForeground(Qt::gray);
|
||||
}
|
||||
m_ruleList->addItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString SettingsView::ruleToString(const Rule &rule) const {
|
||||
QString status = rule.enabled ? "●" : "○";
|
||||
return QString("%1 %2 (Priority: %3)").arg(status, rule.name, QString::number(rule.priority));
|
||||
}
|
||||
|
||||
// ========== Template Slots ==========
|
||||
void SettingsView::onTemplateSelectionChanged() {
|
||||
bool hasSelection = m_templateList->currentRow() >= 0;
|
||||
m_templateEditBtn->setEnabled(hasSelection);
|
||||
m_templateDeleteBtn->setEnabled(hasSelection);
|
||||
}
|
||||
|
||||
void SettingsView::onTemplateAddClicked() {
|
||||
TemplateEditorDialog dlg(Template(), -1, this);
|
||||
connect(&dlg, &TemplateEditorDialog::templateSaved, this, [this](const Template& tmpl) {
|
||||
emit templateAddRequested(tmpl);
|
||||
});
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void SettingsView::onTemplateEditClicked() {
|
||||
int row = m_templateList->currentRow();
|
||||
if (row < 0) return;
|
||||
|
||||
QListWidgetItem *item = m_templateList->item(row);
|
||||
qint64 tmplId = item->data(Qt::UserRole).toLongLong();
|
||||
std::optional<Template> tmplOpt = TemplateDao::findById(tmplId);
|
||||
if (!tmplOpt.has_value()) return;
|
||||
|
||||
TemplateEditorDialog dlg(*tmplOpt, -1, this);
|
||||
connect(&dlg, &TemplateEditorDialog::templateSaved, this, [this](const Template& tmpl) {
|
||||
emit templateEditRequested(tmpl);
|
||||
});
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void SettingsView::onTemplateDeleteClicked() {
|
||||
int row = m_templateList->currentRow();
|
||||
if (row < 0) return;
|
||||
|
||||
QListWidgetItem *item = m_templateList->item(row);
|
||||
qint64 tmplId = item->data(Qt::UserRole).toLongLong();
|
||||
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setWindowTitle(tr("Delete Template"));
|
||||
msgBox.setText(tr("Are you sure you want to delete this template?"));
|
||||
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
msgBox.setDefaultButton(QMessageBox::No);
|
||||
if (msgBox.exec() == QMessageBox::Yes) {
|
||||
emit templateDeleteRequested(tmplId);
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsView::loadTemplates() {
|
||||
m_templateList->clear();
|
||||
|
||||
// Load global templates
|
||||
QVector<Template> globalTmpls = TemplateDao::findGlobal();
|
||||
for (const Template &tmpl : globalTmpls) {
|
||||
QListWidgetItem *item = new QListWidgetItem(templateToString(tmpl));
|
||||
item->setData(Qt::UserRole, tmpl.id);
|
||||
if (tmpl.isDefault) {
|
||||
item->setFont(QFont("Segoe UI", 9, QFont::Bold));
|
||||
}
|
||||
m_templateList->addItem(item);
|
||||
}
|
||||
|
||||
// Load account-specific templates
|
||||
if (m_selectedAccountId > 0) {
|
||||
QVector<Template> accountTmpls = TemplateDao::findByAccount(m_selectedAccountId);
|
||||
for (const Template &tmpl : accountTmpls) {
|
||||
QListWidgetItem *item = new QListWidgetItem(templateToString(tmpl));
|
||||
item->setData(Qt::UserRole, tmpl.id);
|
||||
if (tmpl.isDefault) {
|
||||
item->setFont(QFont("Segoe UI", 9, QFont::Bold));
|
||||
}
|
||||
m_templateList->addItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString SettingsView::templateToString(const Template &tmpl) const {
|
||||
QString status = tmpl.isDefault ? "★ " : "";
|
||||
return QString("%1%2 (%3 vars)").arg(status, tmpl.name, QString::number(tmpl.variables.size()));
|
||||
}
|
||||
|
||||
// ========== Signature Slots ==========
|
||||
void SettingsView::onSignatureSelectionChanged() {
|
||||
bool hasSelection = m_signatureList->currentRow() >= 0;
|
||||
m_signatureEditBtn->setEnabled(hasSelection);
|
||||
m_signatureDeleteBtn->setEnabled(hasSelection);
|
||||
}
|
||||
|
||||
void SettingsView::onSignatureAddClicked() {
|
||||
SignatureEditorDialog dlg(QString(), this);
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
Signature sig;
|
||||
sig.name = dlg.getSignatureName();
|
||||
sig.html = dlg.getSignatureHtml();
|
||||
sig.accountId = -1; // Global by default
|
||||
emit signatureAddRequested(sig);
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsView::onSignatureEditClicked() {
|
||||
int row = m_signatureList->currentRow();
|
||||
if (row < 0) return;
|
||||
|
||||
QListWidgetItem *item = m_signatureList->item(row);
|
||||
qint64 sigId = item->data(Qt::UserRole).toLongLong();
|
||||
|
||||
std::optional<Signature> sigOpt = SignatureDao::findById(sigId);
|
||||
if (!sigOpt.has_value()) return;
|
||||
|
||||
Signature sig = *sigOpt;
|
||||
|
||||
SignatureEditorDialog dlg(sig.html, this);
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
sig.name = dlg.getSignatureName();
|
||||
sig.html = dlg.getSignatureHtml();
|
||||
emit signatureEditRequested(sig);
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsView::onSignatureDeleteClicked() {
|
||||
int row = m_signatureList->currentRow();
|
||||
if (row < 0) return;
|
||||
|
||||
QListWidgetItem *item = m_signatureList->item(row);
|
||||
qint64 sigId = item->data(Qt::UserRole).toLongLong();
|
||||
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setWindowTitle(tr("Delete Signature"));
|
||||
msgBox.setText(tr("Are you sure you want to delete this signature?"));
|
||||
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
msgBox.setDefaultButton(QMessageBox::No);
|
||||
if (msgBox.exec() == QMessageBox::Yes) {
|
||||
emit signatureDeleteRequested(sigId);
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsView::loadSignatures() {
|
||||
m_signatureList->clear();
|
||||
|
||||
// Load global signatures
|
||||
QVector<Signature> globalSigs = SignatureDao::findGlobal();
|
||||
for (const Signature &sig : globalSigs) {
|
||||
QListWidgetItem *item = new QListWidgetItem(sig.name);
|
||||
item->setData(Qt::UserRole, sig.id);
|
||||
m_signatureList->addItem(item);
|
||||
}
|
||||
|
||||
// Load account-specific signatures
|
||||
if (m_selectedAccountId > 0) {
|
||||
QVector<Signature> accountSigs = SignatureDao::findByAccount(m_selectedAccountId);
|
||||
for (const Signature &sig : accountSigs) {
|
||||
QListWidgetItem *item = new QListWidgetItem(sig.name);
|
||||
item->setData(Qt::UserRole, sig.id);
|
||||
m_signatureList->addItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString SettingsView::signatureToString(const Signature &sig) const {
|
||||
return sig.name;
|
||||
}
|
||||
Reference in New Issue
Block a user