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

1151 lines
44 KiB
C++
Raw Normal View History

#include "settingsview.h"
#include "services/preferencesservice.h"
#include "services/startupbehaviorservice.h"
#include "services/translationservice.h"
#include "services/aiactionoptionsservice.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>
#include <QSpinBox>
#include <QFileDialog>
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(createPreferencesTab(), tr("Preferences"));
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;
}
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;
}
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;
}