Files
wino-mail-dtkqt/src/ui/settingsview.cpp
T

951 lines
35 KiB
C++
Raw Normal View History

#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>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QListWidget>
#include <QPushButton>
#include <QLabel>
#include <QFont>
#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();
}
void SettingsView::setupUI() {
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
m_tabWidget = new QTabWidget();
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);
}
QWidget* SettingsView::createAccountsTab() {
QWidget *widget = new QWidget();
QVBoxLayout *layout = new QVBoxLayout(widget);
layout->setContentsMargins(20, 20, 20, 20);
QLabel *title = new QLabel(tr("Email Accounts"));
QFont titleFont = title->font();
titleFont.setPointSize(16);
titleFont.setBold(true);
title->setFont(titleFont);
layout->addWidget(title);
m_accountList = new QListWidget();
m_accountList->setSelectionMode(QAbstractItemView::SingleSelection);
m_accountList->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; }"
);
layout->addWidget(m_accountList);
QHBoxLayout *buttonLayout = new QHBoxLayout();
m_addBtn = new QPushButton(tr("Add Account"));
m_addBtn->setStyleSheet(
"QPushButton { background: #1976D2; color: white; border: none; border-radius: 4px; "
"padding: 8px 16px; font-weight: bold; }"
"QPushButton:hover { background: #1565C0; }"
);
buttonLayout->addWidget(m_addBtn);
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(tr("Delete"));
m_deleteBtn->setEnabled(false);
m_deleteBtn->setStyleSheet(
"QPushButton { background: #EF5350; color: white; border: none; border-radius: 4px; "
"padding: 8px 16px; font-weight: bold; }"
"QPushButton:hover { background: #E53935; }"
);
buttonLayout->addWidget(m_editBtn);
buttonLayout->addWidget(m_deleteBtn);
buttonLayout->addStretch();
layout->addLayout(buttonLayout);
connect(m_accountList, &QListWidget::itemSelectionChanged, this, &SettingsView::onAccountSelectionChanged);
connect(m_editBtn, &QPushButton::clicked, this, &SettingsView::onEditClicked);
connect(m_deleteBtn, &QPushButton::clicked, this, &SettingsView::onDeleteClicked);
connect(m_addBtn, &QPushButton::clicked, this, &SettingsView::accountAddRequested);
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(tr("General Settings"));
QFont titleFont = title->font();
titleFont.setPointSize(16);
titleFont.setBold(true);
title->setFont(titleFont);
layout->addWidget(title);
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(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(tr("Minimize to tray on close"));
minimizeToTray->setChecked(true);
connect(minimizeToTray, &QCheckBox::toggled, this, [this](bool checked) {
emit settingChanged("minimize_to_tray", QVariant(checked));
});
layout->addWidget(minimizeToTray);
layout->addStretch();
return widget;
}
QWidget* SettingsView::createAppearanceTab() {
QWidget *widget = new QWidget();
QVBoxLayout *layout = new QVBoxLayout(widget);
layout->setContentsMargins(20, 20, 20, 20);
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(tr("Theme"));
QFont labelFont = themeLabel->font();
labelFont.setBold(true);
themeLabel->setFont(labelFont);
layout->addWidget(themeLabel);
m_themeGroup = new QButtonGroup(this);
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);
QHBoxLayout *themeLayout = new QHBoxLayout();
themeLayout->addWidget(lightRadio);
themeLayout->addWidget(darkRadio);
themeLayout->addWidget(systemRadio);
layout->addLayout(themeLayout);
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;
}
emit themeChanged(theme);
});
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));
});
layout->addWidget(deepinTheme);
layout->addStretch();
return widget;
}
// ========== Slots for Accounts ==========
void SettingsView::setAccountService(AccountService *service) {
m_accountService = service;
if (m_accountService) {
loadAccounts();
connect(m_accountService, &AccountService::accountListChanged, this, &SettingsView::onAccountListChanged);
}
}
void SettingsView::onAccountListChanged() {
loadAccounts();
}
void SettingsView::loadAccounts() {
if (!m_accountService) {
qDebug() << "AccountService not set";
return;
}
m_accountList->clear();
QList<Account> accounts = m_accountService->getAllAccounts();
qDebug() << "Loaded" << accounts.size() << "accounts from AccountService";
for (const Account &acc : accounts) {
QString display = acc.displayName().isEmpty() ? acc.email() : acc.displayName();
QString text = QString("%1 (%2)").arg(acc.email(), display);
QListWidgetItem *item = new QListWidgetItem(text, m_accountList);
item->setData(Qt::UserRole, acc.id());
m_accountList->addItem(item);
}
if (m_accountList->count() > 0) {
m_accountList->setCurrentRow(0);
}
}
void SettingsView::onAccountSelectionChanged() {
QList<QListWidgetItem*> items = m_accountList->selectedItems();
qDebug() << "SettingsView::onAccountSelectionChanged, selected items count:" << items.size();
if (items.isEmpty()) {
m_selectedAccountId = -1;
m_editBtn->setEnabled(false);
m_deleteBtn->setEnabled(false);
return;
}
QListWidgetItem *item = items.first();
m_selectedAccountId = item->data(Qt::UserRole).toInt();
qDebug() << "SettingsView::onAccountSelectionChanged, selected account id:" << m_selectedAccountId;
m_editBtn->setEnabled(true);
m_deleteBtn->setEnabled(true);
}
void SettingsView::onEditClicked() {
qDebug() << "SettingsView::onEditClicked called, selected account id:" << m_selectedAccountId;
if (m_selectedAccountId != -1 && m_accountService) {
emit accountEditRequested(m_selectedAccountId);
}
}
void SettingsView::onDeleteClicked() {
if (m_selectedAccountId != -1 && m_accountService) {
QMessageBox msgBox(this);
msgBox.setWindowTitle(tr("Delete Account"));
Account* account = m_accountService->findAccountById(m_selectedAccountId);
QString accountName = account ? account->email() : QString::number(m_selectedAccountId);
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) {
emit accountDeleteRequested(m_selectedAccountId);
}
}
}
// ========== 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;
}