2026-08-24 10:29:13 +02:00
|
|
|
#include "settingsview.h"
|
2026-08-28 02:27:46 +02:00
|
|
|
#include "services/preferencesservice.h"
|
|
|
|
|
#include "services/startupbehaviorservice.h"
|
|
|
|
|
#include "services/translationservice.h"
|
|
|
|
|
#include "services/aiactionoptionsservice.h"
|
2026-08-24 10:29:13 +02:00
|
|
|
#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"
|
2026-06-17 22:44:27 +02:00
|
|
|
|
2026-07-05 10:45:44 +02:00
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
#include <QHBoxLayout>
|
|
|
|
|
#include <QListWidget>
|
|
|
|
|
#include <QPushButton>
|
|
|
|
|
#include <QLabel>
|
|
|
|
|
#include <QFont>
|
|
|
|
|
#include <QButtonGroup>
|
|
|
|
|
#include <QComboBox>
|
|
|
|
|
#include <QCheckBox>
|
2026-08-24 10:29:13 +02:00
|
|
|
#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>
|
2026-08-28 02:27:46 +02:00
|
|
|
#include <QSpinBox>
|
|
|
|
|
#include <QFileDialog>
|
2026-07-05 10:45:44 +02:00
|
|
|
|
2026-06-17 22:44:27 +02:00
|
|
|
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();
|
2026-08-24 10:29:13 +02:00
|
|
|
m_tabWidget->addTab(createAccountsTab(), tr("Accounts"));
|
2026-08-28 02:27:46 +02:00
|
|
|
m_tabWidget->addTab(createPreferencesTab(), tr("Preferences"));
|
2026-08-24 10:29:13 +02:00
|
|
|
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"));
|
2026-06-17 22:44:27 +02:00
|
|
|
|
|
|
|
|
mainLayout->addWidget(m_tabWidget);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QWidget* SettingsView::createAccountsTab() {
|
2026-07-05 10:45:44 +02:00
|
|
|
QWidget *widget = new QWidget();
|
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout(widget);
|
2026-06-17 22:44:27 +02:00
|
|
|
layout->setContentsMargins(20, 20, 20, 20);
|
|
|
|
|
|
2026-08-24 10:29:13 +02:00
|
|
|
QLabel *title = new QLabel(tr("Email Accounts"));
|
2026-07-05 10:45:44 +02:00
|
|
|
QFont titleFont = title->font();
|
2026-06-17 22:44:27 +02:00
|
|
|
titleFont.setPointSize(16);
|
2026-08-24 10:29:13 +02:00
|
|
|
titleFont.setBold(true);
|
2026-07-05 10:45:44 +02:00
|
|
|
title->setFont(titleFont);
|
|
|
|
|
layout->addWidget(title);
|
2026-06-17 22:44:27 +02:00
|
|
|
|
|
|
|
|
m_accountList = new QListWidget();
|
2026-07-05 10:45:44 +02:00
|
|
|
m_accountList->setSelectionMode(QAbstractItemView::SingleSelection);
|
2026-06-17 22:44:27 +02:00
|
|
|
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; }"
|
|
|
|
|
);
|
2026-07-05 10:45:44 +02:00
|
|
|
layout->addWidget(m_accountList);
|
2026-06-17 22:44:27 +02:00
|
|
|
|
2026-07-05 10:45:44 +02:00
|
|
|
QHBoxLayout *buttonLayout = new QHBoxLayout();
|
2026-08-24 10:29:13 +02:00
|
|
|
m_addBtn = new QPushButton(tr("Add Account"));
|
2026-07-05 10:45:44 +02:00
|
|
|
m_addBtn->setStyleSheet(
|
2026-08-24 10:29:13 +02:00
|
|
|
"QPushButton { background: #1976D2; color: white; border: none; border-radius: 4px; "
|
2026-07-05 10:45:44 +02:00
|
|
|
"padding: 8px 16px; font-weight: bold; }"
|
2026-08-24 10:29:13 +02:00
|
|
|
"QPushButton:hover { background: #1565C0; }"
|
2026-06-17 22:44:27 +02:00
|
|
|
);
|
2026-07-05 10:45:44 +02:00
|
|
|
buttonLayout->addWidget(m_addBtn);
|
2026-08-24 10:29:13 +02:00
|
|
|
|
|
|
|
|
m_editBtn = new QPushButton(tr("Edit"));
|
2026-07-05 10:45:44 +02:00
|
|
|
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; }"
|
|
|
|
|
);
|
2026-08-24 10:29:13 +02:00
|
|
|
m_deleteBtn = new QPushButton(tr("Delete"));
|
2026-07-05 10:45:44 +02:00
|
|
|
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);
|
2026-06-17 22:44:27 +02:00
|
|
|
|
2026-07-05 10:45:44 +02:00
|
|
|
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;
|
2026-06-17 22:44:27 +02:00
|
|
|
}
|
|
|
|
|
|
2026-08-24 10:29:13 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-17 22:44:27 +02:00
|
|
|
QWidget* SettingsView::createGeneralTab() {
|
2026-07-05 10:45:44 +02:00
|
|
|
QWidget *widget = new QWidget();
|
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout(widget);
|
2026-06-17 22:44:27 +02:00
|
|
|
layout->setContentsMargins(20, 20, 20, 20);
|
|
|
|
|
|
2026-08-24 10:29:13 +02:00
|
|
|
QLabel *title = new QLabel(tr("General Settings"));
|
2026-07-05 10:45:44 +02:00
|
|
|
QFont titleFont = title->font();
|
2026-06-17 22:44:27 +02:00
|
|
|
titleFont.setPointSize(16);
|
2026-08-24 10:29:13 +02:00
|
|
|
titleFont.setBold(true);
|
2026-07-05 10:45:44 +02:00
|
|
|
title->setFont(titleFont);
|
|
|
|
|
layout->addWidget(title);
|
2026-06-17 22:44:27 +02:00
|
|
|
|
2026-08-24 10:29:13 +02:00
|
|
|
QCheckBox *startOnLogin = new QCheckBox(tr("Start application on login"));
|
2026-06-17 22:44:27 +02:00
|
|
|
startOnLogin->setChecked(true);
|
2026-07-05 10:45:44 +02:00
|
|
|
connect(startOnLogin, &QCheckBox::toggled, this, [this](bool checked) {
|
|
|
|
|
emit settingChanged("start_on_login", QVariant(checked));
|
2026-06-17 22:44:27 +02:00
|
|
|
});
|
|
|
|
|
layout->addWidget(startOnLogin);
|
|
|
|
|
|
2026-08-24 10:29:13 +02:00
|
|
|
QCheckBox *enableNotifications = new QCheckBox(tr("Enable notifications"));
|
2026-06-17 22:44:27 +02:00
|
|
|
enableNotifications->setChecked(true);
|
2026-07-05 10:45:44 +02:00
|
|
|
connect(enableNotifications, &QCheckBox::toggled, this, [this](bool checked) {
|
|
|
|
|
emit settingChanged("enable_notifications", QVariant(checked));
|
2026-06-17 22:44:27 +02:00
|
|
|
});
|
|
|
|
|
layout->addWidget(enableNotifications);
|
|
|
|
|
|
2026-08-24 10:29:13 +02:00
|
|
|
QCheckBox *minimizeToTray = new QCheckBox(tr("Minimize to tray on close"));
|
2026-06-17 22:44:27 +02:00
|
|
|
minimizeToTray->setChecked(true);
|
2026-07-05 10:45:44 +02:00
|
|
|
connect(minimizeToTray, &QCheckBox::toggled, this, [this](bool checked) {
|
|
|
|
|
emit settingChanged("minimize_to_tray", QVariant(checked));
|
2026-06-17 22:44:27 +02:00
|
|
|
});
|
|
|
|
|
layout->addWidget(minimizeToTray);
|
|
|
|
|
|
|
|
|
|
layout->addStretch();
|
2026-07-05 10:45:44 +02:00
|
|
|
return widget;
|
2026-06-17 22:44:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QWidget* SettingsView::createAppearanceTab() {
|
2026-07-05 10:45:44 +02:00
|
|
|
QWidget *widget = new QWidget();
|
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout(widget);
|
2026-06-17 22:44:27 +02:00
|
|
|
layout->setContentsMargins(20, 20, 20, 20);
|
|
|
|
|
|
2026-08-24 10:29:13 +02:00
|
|
|
QLabel *title = new QLabel(tr("Appearance"));
|
2026-07-05 10:45:44 +02:00
|
|
|
QFont titleFont = title->font();
|
2026-06-17 22:44:27 +02:00
|
|
|
titleFont.setPointSize(16);
|
2026-08-24 10:29:13 +02:00
|
|
|
titleFont.setBold(true);
|
2026-07-05 10:45:44 +02:00
|
|
|
title->setFont(titleFont);
|
|
|
|
|
layout->addWidget(title);
|
2026-06-17 22:44:27 +02:00
|
|
|
|
2026-08-24 10:29:13 +02:00
|
|
|
QLabel *themeLabel = new QLabel(tr("Theme"));
|
2026-07-05 10:45:44 +02:00
|
|
|
QFont labelFont = themeLabel->font();
|
|
|
|
|
labelFont.setBold(true);
|
|
|
|
|
themeLabel->setFont(labelFont);
|
2026-06-17 22:44:27 +02:00
|
|
|
layout->addWidget(themeLabel);
|
|
|
|
|
|
|
|
|
|
m_themeGroup = new QButtonGroup(this);
|
2026-08-24 10:29:13 +02:00
|
|
|
QRadioButton *lightRadio = new QRadioButton(tr("Light"));
|
|
|
|
|
QRadioButton *darkRadio = new QRadioButton(tr("Dark"));
|
|
|
|
|
QRadioButton *systemRadio = new QRadioButton(tr("System"));
|
2026-06-17 22:44:27 +02:00
|
|
|
m_themeGroup->addButton(lightRadio, 0);
|
|
|
|
|
m_themeGroup->addButton(darkRadio, 1);
|
|
|
|
|
m_themeGroup->addButton(systemRadio, 2);
|
|
|
|
|
|
2026-07-05 10:45:44 +02:00
|
|
|
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) {
|
2026-06-17 22:44:27 +02:00
|
|
|
QString theme;
|
|
|
|
|
switch (id) {
|
2026-08-24 10:29:13 +02:00
|
|
|
case 0: theme = "light"; break;
|
|
|
|
|
case 1: theme = "dark"; break;
|
|
|
|
|
case 2: theme = "system"; break;
|
2026-06-17 22:44:27 +02:00
|
|
|
}
|
|
|
|
|
emit themeChanged(theme);
|
|
|
|
|
});
|
|
|
|
|
|
2026-08-24 10:29:13 +02:00
|
|
|
QCheckBox *deepinTheme = new QCheckBox(tr("Deepin theme (experimental)"));
|
2026-06-17 22:44:27 +02:00
|
|
|
deepinTheme->setChecked(true);
|
2026-07-05 10:45:44 +02:00
|
|
|
connect(deepinTheme, &QCheckBox::toggled, this, [this](bool checked) {
|
|
|
|
|
emit settingChanged("deepin_theme", QVariant(checked));
|
2026-06-17 22:44:27 +02:00
|
|
|
});
|
|
|
|
|
layout->addWidget(deepinTheme);
|
|
|
|
|
|
|
|
|
|
layout->addStretch();
|
2026-07-05 10:45:44 +02:00
|
|
|
return widget;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-28 02:27:46 +02:00
|
|
|
QWidget* SettingsView::createPreferencesTab() {
|
|
|
|
|
QWidget *widget = new QWidget();
|
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout(widget);
|
|
|
|
|
layout->setContentsMargins(20, 20, 20, 20);
|
|
|
|
|
layout->setSpacing(16);
|
|
|
|
|
|
|
|
|
|
QLabel *title = new QLabel(tr("Preferences"));
|
|
|
|
|
QFont titleFont = title->font();
|
|
|
|
|
titleFont.setPointSize(16);
|
|
|
|
|
titleFont.setBold(true);
|
|
|
|
|
title->setFont(titleFont);
|
|
|
|
|
layout->addWidget(title);
|
|
|
|
|
|
|
|
|
|
// Search Mode
|
|
|
|
|
QGroupBox *searchGroup = new QGroupBox(tr("Search"));
|
|
|
|
|
QFormLayout *searchLayout = new QFormLayout(searchGroup);
|
|
|
|
|
|
|
|
|
|
m_searchModeCombo = new QComboBox();
|
|
|
|
|
m_searchModeCombo->addItem(tr("Local"), QVariant(static_cast<int>(SearchMode::Local)));
|
|
|
|
|
m_searchModeCombo->addItem(tr("Online"), QVariant(static_cast<int>(SearchMode::Online)));
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_searchModeCombo->setCurrentIndex(static_cast<int>(m_preferencesService->defaultSearchMode()));
|
|
|
|
|
}
|
|
|
|
|
connect(m_searchModeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_preferencesService->setDefaultSearchMode(static_cast<SearchMode>(m_searchModeCombo->itemData(index).toInt()));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
searchLayout->addRow(tr("Default search mode:"), m_searchModeCombo);
|
|
|
|
|
layout->addWidget(searchGroup);
|
|
|
|
|
|
|
|
|
|
// Default App Mode
|
|
|
|
|
QGroupBox *appModeGroup = new QGroupBox(tr("Default Application Mode"));
|
|
|
|
|
QFormLayout *appModeLayout = new QFormLayout(appModeGroup);
|
|
|
|
|
|
|
|
|
|
m_defaultAppModeCombo = new QComboBox();
|
|
|
|
|
m_defaultAppModeCombo->addItem(tr("Mail"), QVariant(static_cast<int>(WinoApplicationMode::Mail)));
|
|
|
|
|
m_defaultAppModeCombo->addItem(tr("Calendar"), QVariant(static_cast<int>(WinoApplicationMode::Calendar)));
|
|
|
|
|
m_defaultAppModeCombo->addItem(tr("Contacts"), QVariant(static_cast<int>(WinoApplicationMode::Contacts)));
|
|
|
|
|
m_defaultAppModeCombo->addItem(tr("Settings"), QVariant(static_cast<int>(WinoApplicationMode::Settings)));
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_defaultAppModeCombo->setCurrentIndex(static_cast<int>(m_preferencesService->defaultApplicationMode()));
|
|
|
|
|
}
|
|
|
|
|
connect(m_defaultAppModeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_preferencesService->setDefaultApplicationMode(static_cast<WinoApplicationMode>(m_defaultAppModeCombo->itemData(index).toInt()));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
appModeLayout->addRow(tr("Default mode on startup:"), m_defaultAppModeCombo);
|
|
|
|
|
layout->addWidget(appModeGroup);
|
|
|
|
|
|
|
|
|
|
// Language
|
|
|
|
|
QGroupBox *languageGroup = new QGroupBox(tr("Language"));
|
|
|
|
|
QFormLayout *languageLayout = new QFormLayout(languageGroup);
|
|
|
|
|
|
|
|
|
|
m_languageCombo = new QComboBox();
|
|
|
|
|
if (m_translationService) {
|
|
|
|
|
QVector<AppLanguageModel> languages = m_translationService->getAvailableLanguages();
|
|
|
|
|
for (const AppLanguageModel &lang : languages) {
|
|
|
|
|
m_languageCombo->addItem(lang.displayName, lang.language);
|
|
|
|
|
}
|
|
|
|
|
int idx = m_languageCombo->findData(m_translationService->currentLanguage());
|
|
|
|
|
if (idx >= 0) m_languageCombo->setCurrentIndex(idx);
|
|
|
|
|
}
|
|
|
|
|
connect(m_languageCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
|
|
|
|
if (m_translationService) {
|
|
|
|
|
m_translationService->setLanguage(m_languageCombo->itemData(index).toString());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
languageLayout->addRow(tr("Interface language:"), m_languageCombo);
|
|
|
|
|
layout->addWidget(languageGroup);
|
|
|
|
|
|
|
|
|
|
// Email Sync Interval
|
|
|
|
|
QGroupBox *syncGroup = new QGroupBox(tr("Email Synchronization"));
|
|
|
|
|
QFormLayout *syncLayout = new QFormLayout(syncGroup);
|
|
|
|
|
|
|
|
|
|
m_syncIntervalSpin = new QSpinBox();
|
|
|
|
|
m_syncIntervalSpin->setRange(1, 1440); // 1 minute to 24 hours
|
|
|
|
|
m_syncIntervalSpin->setSuffix(tr(" minutes"));
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_syncIntervalSpin->setValue(m_preferencesService->emailSyncIntervalMinutes());
|
|
|
|
|
}
|
|
|
|
|
connect(m_syncIntervalSpin, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int value) {
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_preferencesService->setEmailSyncIntervalMinutes(value);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
syncLayout->addRow(tr("Sync interval:"), m_syncIntervalSpin);
|
|
|
|
|
layout->addWidget(syncGroup);
|
|
|
|
|
|
|
|
|
|
// Startup Behavior
|
|
|
|
|
QGroupBox *startupGroup = new QGroupBox(tr("Startup"));
|
|
|
|
|
QFormLayout *startupLayout = new QFormLayout(startupGroup);
|
|
|
|
|
|
|
|
|
|
m_startOnLoginCheck = new QCheckBox(tr("Start application on login"));
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_startOnLoginCheck->setChecked(m_preferencesService->startOnLogin());
|
|
|
|
|
}
|
|
|
|
|
connect(m_startOnLoginCheck, &QCheckBox::toggled, this, [this](bool checked) {
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_preferencesService->setStartOnLogin(checked);
|
|
|
|
|
}
|
|
|
|
|
if (m_startupBehaviorService) {
|
|
|
|
|
m_startupBehaviorService->toggleStartupBehavior(checked);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
startupLayout->addRow(m_startOnLoginCheck);
|
|
|
|
|
|
|
|
|
|
m_minimizeToTrayCheck = new QCheckBox(tr("Minimize to tray on close"));
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_minimizeToTrayCheck->setChecked(m_preferencesService->minimizeToTray());
|
|
|
|
|
}
|
|
|
|
|
connect(m_minimizeToTrayCheck, &QCheckBox::toggled, this, [this](bool checked) {
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_preferencesService->setMinimizeToTray(checked);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
startupLayout->addRow(m_minimizeToTrayCheck);
|
|
|
|
|
|
|
|
|
|
m_enableNotificationsCheck = new QCheckBox(tr("Enable notifications"));
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_enableNotificationsCheck->setChecked(m_preferencesService->enableNotifications());
|
|
|
|
|
}
|
|
|
|
|
connect(m_enableNotificationsCheck, &QCheckBox::toggled, this, [this](bool checked) {
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_preferencesService->setEnableNotifications(checked);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
startupLayout->addRow(m_enableNotificationsCheck);
|
|
|
|
|
layout->addWidget(startupGroup);
|
|
|
|
|
|
|
|
|
|
// AI Translation
|
|
|
|
|
QGroupBox *aiGroup = new QGroupBox(tr("AI Translation"));
|
|
|
|
|
QFormLayout *aiLayout = new QFormLayout(aiGroup);
|
|
|
|
|
|
|
|
|
|
m_translateLanguageCombo = new QComboBox();
|
|
|
|
|
if (m_aiActionOptionsService) {
|
|
|
|
|
QVector<AiTranslateLanguageOption> options = m_aiActionOptionsService->getTranslateLanguageOptions();
|
|
|
|
|
for (const AiTranslateLanguageOption &opt : options) {
|
|
|
|
|
m_translateLanguageCombo->addItem(opt.displayName, opt.code);
|
|
|
|
|
}
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
int idx = m_translateLanguageCombo->findData(m_preferencesService->aiDefaultTranslationLanguageCode());
|
|
|
|
|
if (idx >= 0) m_translateLanguageCombo->setCurrentIndex(idx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
connect(m_translateLanguageCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_preferencesService->setAiDefaultTranslationLanguageCode(m_translateLanguageCombo->itemData(index).toString());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
aiLayout->addRow(tr("Default translation language:"), m_translateLanguageCombo);
|
|
|
|
|
|
|
|
|
|
m_summarizeLanguageCombo = new QComboBox();
|
|
|
|
|
if (m_aiActionOptionsService) {
|
|
|
|
|
QVector<AiTranslateLanguageOption> options = m_aiActionOptionsService->getTranslateLanguageOptions();
|
|
|
|
|
for (const AiTranslateLanguageOption &opt : options) {
|
|
|
|
|
m_summarizeLanguageCombo->addItem(opt.displayName, opt.code);
|
|
|
|
|
}
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
int idx = m_summarizeLanguageCombo->findData(m_preferencesService->aiSummarizeLanguageCode());
|
|
|
|
|
if (idx >= 0) m_summarizeLanguageCombo->setCurrentIndex(idx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
connect(m_summarizeLanguageCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_preferencesService->setAiSummarizeLanguageCode(m_summarizeLanguageCombo->itemData(index).toString());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
aiLayout->addRow(tr("Summarize language:"), m_summarizeLanguageCombo);
|
|
|
|
|
|
|
|
|
|
m_summarySavePathEdit = new QLineEdit();
|
|
|
|
|
m_summarySavePathEdit->setPlaceholderText(tr("Select folder for AI summaries..."));
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_summarySavePathEdit->setText(m_preferencesService->aiSummarySavePath());
|
|
|
|
|
}
|
|
|
|
|
m_summarySavePathBtn = new QPushButton(tr("Browse..."));
|
|
|
|
|
connect(m_summarySavePathBtn, &QPushButton::clicked, this, [this]() {
|
|
|
|
|
QString path = QFileDialog::getExistingDirectory(this, tr("Select Summary Save Folder"),
|
|
|
|
|
m_summarySavePathEdit->text());
|
|
|
|
|
if (!path.isEmpty()) {
|
|
|
|
|
m_summarySavePathEdit->setText(path);
|
|
|
|
|
if (m_preferencesService) {
|
|
|
|
|
m_preferencesService->setAiSummarySavePath(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
QHBoxLayout *pathLayout = new QHBoxLayout();
|
|
|
|
|
pathLayout->addWidget(m_summarySavePathEdit);
|
|
|
|
|
pathLayout->addWidget(m_summarySavePathBtn);
|
|
|
|
|
aiLayout->addRow(tr("Summary save path:"), pathLayout);
|
|
|
|
|
layout->addWidget(aiGroup);
|
|
|
|
|
|
|
|
|
|
layout->addStretch();
|
|
|
|
|
return widget;
|
|
|
|
|
}
|
2026-07-05 10:45:44 +02:00
|
|
|
void SettingsView::setAccountService(AccountService *service) {
|
|
|
|
|
m_accountService = service;
|
|
|
|
|
if (m_accountService) {
|
|
|
|
|
loadAccounts();
|
|
|
|
|
connect(m_accountService, &AccountService::accountListChanged, this, &SettingsView::onAccountListChanged);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-30 01:46:34 +02:00
|
|
|
void SettingsView::setPreferencesService(PreferencesService *service) {
|
|
|
|
|
m_preferencesService = service;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SettingsView::setStartupBehaviorService(StartupBehaviorService *service) {
|
|
|
|
|
m_startupBehaviorService = service;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SettingsView::setTranslationService(TranslationService *service) {
|
|
|
|
|
m_translationService = service;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SettingsView::setAiActionOptionsService(AiActionOptionsService *service) {
|
|
|
|
|
m_aiActionOptionsService = service;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-05 10:45:44 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-24 10:29:13 +02:00
|
|
|
|
|
|
|
|
void SettingsView::onAccountSelectionChanged() {
|
2026-07-05 10:45:44 +02:00
|
|
|
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);
|
2026-08-24 10:29:13 +02:00
|
|
|
msgBox.setWindowTitle(tr("Delete Account"));
|
2026-07-05 10:45:44 +02:00
|
|
|
Account* account = m_accountService->findAccountById(m_selectedAccountId);
|
|
|
|
|
QString accountName = account ? account->email() : QString::number(m_selectedAccountId);
|
2026-08-24 10:29:13 +02:00
|
|
|
msgBox.setText(tr("Are you sure you want to delete the account \"%1\"?").arg(accountName));
|
2026-07-05 10:45:44 +02:00
|
|
|
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
|
|
|
|
msgBox.setDefaultButton(QMessageBox::No);
|
|
|
|
|
if (msgBox.exec() == QMessageBox::Yes) {
|
|
|
|
|
emit accountDeleteRequested(m_selectedAccountId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-24 10:29:13 +02:00
|
|
|
|
|
|
|
|
// ========== 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;
|
2026-08-28 13:45:21 +02:00
|
|
|
}
|
|
|
|
|
SettingsView::~SettingsView() = default;
|