Files
wino-mail-dtkqt/src/ui/signaturemanagerdialog.cpp
T
javier 0bb8738607 feat: comprehensive Wino Mail updates
- ReaderView: complete rewrite with CSS styling, headers, attachments, zoom, find, dark mode, image blocking
- Categories: DAO + UI tree widget with colors, nested categories, assignment
- Rules engine: DAO + evaluation + actions (move, mark read, flag, delete, category, forward)
- Templates: DAO + editor + manager with variables support
- Signatures: DAO + manager + auto-per-account + manual selector in compose
- ComposeView: signature combo, template selector, auto-signature on new email
- MainWindow: frameless with rounded corners, 1px border, resize from edges, no status bar
- Database: new tables (Category, MailCategory, Rule, Template, Signature) with indexes
2026-08-23 14:49:58 +02:00

277 lines
10 KiB
C++

#include "signaturemanagerdialog.h"
#include "db/dao/accountdao.h"
#include "services/accountservice.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QLineEdit>
#include <QTextEdit>
#include <QListWidget>
#include <QListWidgetItem>
#include <QDialogButtonBox>
#include <QMessageBox>
#include <QInputDialog>
#include <QDebug>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QMenu>
SignatureEditorDialog::SignatureEditorDialog(const QString& signatureHtml, QWidget *parent)
: QDialog(parent), m_signatureHtml(signatureHtml)
{
setWindowTitle(tr("Editor de firma"));
resize(600, 400);
setupUI();
}
void SignatureEditorDialog::setupUI()
{
QVBoxLayout* mainLayout = new QVBoxLayout(this);
// Name
QHBoxLayout* nameLayout = new QHBoxLayout();
nameLayout->addWidget(new QLabel(tr("Nombre:")));
m_nameEdit = new QLineEdit();
m_nameEdit->setPlaceholderText(tr("Ej: Firma personal, Firma trabajo, etc."));
nameLayout->addWidget(m_nameEdit);
mainLayout->addLayout(nameLayout);
// Editor
m_editor = new QTextEdit();
m_editor->setAcceptRichText(true);
m_editor->setHtml(m_signatureHtml);
m_editor->setPlaceholderText(tr("Escribe tu firma aquí (HTML soportado)..."));
mainLayout->addWidget(m_editor, 1);
// Buttons
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &SignatureEditorDialog::onAccept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
mainLayout->addWidget(buttonBox);
}
void SignatureEditorDialog::onAccept()
{
if (m_nameEdit->text().trimmed().isEmpty()) {
QMessageBox::warning(this, tr("Error"), tr("El nombre de la firma es obligatorio."));
m_nameEdit->setFocus();
return;
}
m_signatureHtml = m_editor->toHtml();
emit signatureSaved(m_nameEdit->text().trimmed(), m_signatureHtml);
accept();
}
SignatureManagerDialog::SignatureManagerDialog(AccountService* accountService, qint64 accountId, QWidget *parent)
: QDialog(parent), m_accountService(accountService), m_accountId(accountId)
{
setWindowTitle(tr("Gestor de firmas"));
resize(500, 400);
setupUI();
loadSignatures();
}
void SignatureManagerDialog::setupUI()
{
QVBoxLayout* mainLayout = new QVBoxLayout(this);
// Header
QLabel* titleLabel = new QLabel(tr("Firmas disponibles"));
titleLabel->setStyleSheet("font-weight: bold; font-size: 14px; padding: 8px;");
mainLayout->addWidget(titleLabel);
// List
m_list = new QListWidget();
m_list->setSelectionMode(QAbstractItemView::SingleSelection);
m_list->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_list, &QListWidget::customContextMenuRequested, this, [this](const QPoint& pos) {
QListWidgetItem* item = m_list->itemAt(pos);
if (!item) return;
QMenu menu(this);
QAction* editAct = menu.addAction(tr("Editar"), [this, item]() { onEditSignature(item); });
QAction* delAct = menu.addAction(tr("Eliminar"), [this, item]() { onDeleteSignature(item); });
menu.exec(m_list->viewport()->mapToGlobal(pos));
});
connect(m_list, &QListWidget::itemClicked, this, &SignatureManagerDialog::onSignatureSelected);
connect(m_list, &QListWidget::itemDoubleClicked, this, &SignatureManagerDialog::onUseSignature);
mainLayout->addWidget(m_list, 1);
// Toolbar
QHBoxLayout* toolLayout = new QHBoxLayout();
m_btnNew = new QPushButton(tr("Nueva firma"));
m_btnEdit = new QPushButton(tr("Editar"));
m_btnDelete = new QPushButton(tr("Eliminar"));
m_btnUse = new QPushButton(tr("Usar"));
m_btnClose = new QPushButton(tr("Cerrar"));
m_btnNew->setStyleSheet("QPushButton { background: #1976D2; color: white; font-weight: bold; padding: 6px 12px; border-radius: 4px; }");
m_btnUse->setStyleSheet("QPushButton { background: #4CAF50; color: white; padding: 6px 12px; border-radius: 4px; }");
m_btnDelete->setStyleSheet("QPushButton { color: #d32f2f; }");
toolLayout->addWidget(m_btnNew);
toolLayout->addWidget(m_btnEdit);
toolLayout->addWidget(m_btnDelete);
toolLayout->addStretch();
toolLayout->addWidget(m_btnUse);
toolLayout->addWidget(m_btnClose);
mainLayout->addLayout(toolLayout);
// Status
QLabel* statusLabel = new QLabel(tr("Selecciona una firma y pulsa 'Usar' para insertarla en el correo."));
statusLabel->setStyleSheet("color: #666; font-size: 11px; padding: 4px;");
mainLayout->addWidget(statusLabel);
// Connect
connect(m_btnNew, &QPushButton::clicked, this, &SignatureManagerDialog::onNewSignature);
connect(m_btnEdit, &QPushButton::clicked, this, [this]() { onEditSignature(m_list->currentItem()); });
connect(m_btnDelete, &QPushButton::clicked, this, [this]() { onDeleteSignature(m_list->currentItem()); });
connect(m_btnUse, &QPushButton::clicked, this, [this]() { onUseSignature(m_list->currentItem()); });
connect(m_btnClose, &QPushButton::clicked, this, &QDialog::accept);
// Disable buttons when no selection
connect(m_list, &QListWidget::itemSelectionChanged, this, [this]() {
bool hasSel = m_list->currentItem() != nullptr;
m_btnEdit->setEnabled(hasSel);
m_btnDelete->setEnabled(hasSel);
m_btnUse->setEnabled(hasSel);
});
}
void SignatureManagerDialog::loadSignatures()
{
m_list->clear();
// For now, we'll use a simple SQLite table for signatures
// In a more complete implementation, this could be per-account
QSqlDatabase db = DatabaseManager::instance().database();
// Create table if not exists
QSqlQuery createQuery(db);
createQuery.exec(
"CREATE TABLE IF NOT EXISTS Signature ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"accountId INTEGER, " // -1 = global
"name TEXT NOT NULL, "
"html TEXT NOT NULL, "
"createdAt DATETIME DEFAULT CURRENT_TIMESTAMP, "
"updatedAt DATETIME DEFAULT CURRENT_TIMESTAMP, "
"FOREIGN KEY(accountId) REFERENCES Account(id) ON DELETE CASCADE"
")"
);
QSqlQuery query(db);
if (m_accountId >= 0) {
query.prepare("SELECT id, name, html FROM Signature WHERE accountId = :accountId OR accountId IS NULL ORDER BY name");
query.bindValue(":accountId", m_accountId);
} else {
query.prepare("SELECT id, name, html FROM Signature WHERE accountId IS NULL ORDER BY name");
}
if (query.exec()) {
while (query.next()) {
QListWidgetItem* item = new QListWidgetItem(query.value("name").toString());
item->setData(Qt::UserRole, query.value("id").toLongLong());
item->setData(Qt::UserRole + 1, query.value("html").toString());
item->setToolTip(query.value("html").toString().left(200) + "...");
m_list->addItem(item);
}
}
}
void SignatureManagerDialog::onNewSignature()
{
SignatureEditorDialog dlg(QString(), this);
connect(&dlg, &SignatureEditorDialog::signatureSaved, this, [this](const QString& name, const QString& html) {
QSqlDatabase db = DatabaseManager::instance().database();
QSqlQuery query(db);
query.prepare("INSERT INTO Signature (accountId, name, html, createdAt, updatedAt) VALUES (:accountId, :name, :html, :createdAt, :updatedAt)");
query.bindValue(":accountId", m_accountId >= 0 ? m_accountId : QVariant());
query.bindValue(":name", name);
query.bindValue(":html", html);
query.bindValue(":createdAt", QDateTime::currentDateTime());
query.bindValue(":updatedAt", QDateTime::currentDateTime());
if (query.exec()) {
loadSignatures();
emit signaturesChanged();
} else {
QMessageBox::warning(this, tr("Error"), tr("No se pudo guardar la firma: %1").arg(query.lastError().text()));
}
});
dlg.exec();
}
void SignatureManagerDialog::onEditSignature(QListWidgetItem* item)
{
if (!item) return;
qint64 id = item->data(Qt::UserRole).toLongLong();
QString html = item->data(Qt::UserRole + 1).toString();
QString name = item->text();
SignatureEditorDialog dlg(html, this);
dlg.setSignatureName(name);
connect(&dlg, &SignatureEditorDialog::signatureSaved, this, [this, id](const QString& name, const QString& html) {
QSqlDatabase db = DatabaseManager::instance().database();
QSqlQuery query(db);
query.prepare("UPDATE Signature SET name = :name, html = :html, updatedAt = :updatedAt WHERE id = :id");
query.bindValue(":id", id);
query.bindValue(":name", name);
query.bindValue(":html", html);
query.bindValue(":updatedAt", QDateTime::currentDateTime());
if (query.exec()) {
loadSignatures();
emit signaturesChanged();
} else {
QMessageBox::warning(this, tr("Error"), tr("No se pudo actualizar la firma: %1").arg(query.lastError().text()));
}
});
dlg.exec();
}
void SignatureManagerDialog::onDeleteSignature(QListWidgetItem* item)
{
if (!item) return;
qint64 id = item->data(Qt::UserRole).toLongLong();
QString name = item->text();
if (QMessageBox::question(this, tr("Eliminar firma"),
tr("¿Eliminar la firma \"%1\"?").arg(name),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
QSqlDatabase db = DatabaseManager::instance().database();
QSqlQuery query(db);
query.prepare("DELETE FROM Signature WHERE id = :id");
query.bindValue(":id", id);
if (query.exec()) {
loadSignatures();
emit signaturesChanged();
} else {
QMessageBox::warning(this, tr("Error"), tr("No se pudo eliminar la firma: %1").arg(query.lastError().text()));
}
}
}
void SignatureManagerDialog::onUseSignature(QListWidgetItem* item)
{
if (!item) return;
m_selectedSignatureHtml = item->data(Qt::UserRole + 1).toString();
emit signatureSelected(m_selectedSignatureHtml);
accept();
}
void SignatureManagerDialog::onSignatureSelected(QListWidgetItem* item)
{
if (item) {
m_selectedSignatureHtml = item->data(Qt::UserRole + 1).toString();
}
}