585 lines
23 KiB
C++
585 lines
23 KiB
C++
#include "ruleditordialog.h"
|
|||
|
|
#include "db/dao/ruledao.h"
|
||
|
|
#include "db/dao/categorydao.h"
|
||
|
|
#include "db/dao/folderdao.h"
|
||
|
|
#include "services/rulesengine.h"
|
||
|
|
#include "services/accountservice.h"
|
||
|
|
#include <QHeaderView>
|
||
|
|
#include <QMessageBox>
|
||
|
|
#include <QInputDialog>
|
||
|
|
#include <QFileDialog>
|
||
|
|
#include <QJsonDocument>
|
||
|
|
#include <QJsonObject>
|
||
|
|
#include <QLabel>
|
||
|
|
#include <QMenu>
|
||
|
|
#include <QSqlDatabase>
|
||
|
|
#include <QSqlQuery>
|
||
|
|
#include <QHBoxLayout>
|
||
|
|
#include <QVBoxLayout>
|
||
|
|
#include <QFormLayout>
|
||
|
|
#include <QTableWidget>
|
||
|
|
#include <QPushButton>
|
||
|
|
#include <QLineEdit>
|
||
|
|
#include <QSpinBox>
|
||
|
|
#include <QCheckBox>
|
||
|
|
#include <QDialogButtonBox>
|
||
|
|
#include <QGroupBox>
|
||
|
|
#include <QDebug>
|
||
|
|
|
||
|
|
RuleEditorDialog::RuleEditorDialog(const Rule& rule, qint64 accountId, QWidget *parent)
|
||
|
|
: QDialog(parent), m_rule(rule), m_accountId(accountId)
|
||
|
|
{
|
||
|
|
setWindowTitle(rule.isValid() ? tr("Editar regla") : tr("Nueva regla"));
|
||
|
|
resize(800, 600);
|
||
|
|
setupUI();
|
||
|
|
populateFromRule();
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::setupUI()
|
||
|
|
{
|
||
|
|
QVBoxLayout* mainLayout = new QVBoxLayout(this);
|
||
|
|
|
||
|
|
// Form header
|
||
|
|
QGroupBox* headerGroup = new QGroupBox(tr("Información básica"));
|
||
|
|
QFormLayout* headerLayout = new QFormLayout(headerGroup);
|
||
|
|
|
||
|
|
m_nameEdit = new QLineEdit();
|
||
|
|
m_nameEdit->setPlaceholderText(tr("Nombre de la regla"));
|
||
|
|
headerLayout->addRow(tr("Nombre:"), m_nameEdit);
|
||
|
|
|
||
|
|
m_descEdit = new QTextEdit();
|
||
|
|
m_descEdit->setMaximumHeight(60);
|
||
|
|
m_descEdit->setPlaceholderText(tr("Descripción opcional"));
|
||
|
|
headerLayout->addRow(tr("Descripción:"), m_descEdit);
|
||
|
|
|
||
|
|
m_accountCombo = new QComboBox();
|
||
|
|
loadAccounts();
|
||
|
|
headerLayout->addRow(tr("Cuenta:"), m_accountCombo);
|
||
|
|
|
||
|
|
QHBoxLayout* optionsLayout = new QHBoxLayout();
|
||
|
|
m_enabledCheck = new QCheckBox(tr("Activada"));
|
||
|
|
m_enabledCheck->setChecked(true);
|
||
|
|
m_matchAllCheck = new QCheckBox(tr("Todas las condiciones (Y)"));
|
||
|
|
m_matchAllCheck->setChecked(true);
|
||
|
|
m_matchAllCheck->setToolTip(tr("Desactivar = Cualquier condición (O)"));
|
||
|
|
m_prioritySpin = new QSpinBox();
|
||
|
|
m_prioritySpin->setRange(1, 999);
|
||
|
|
m_prioritySpin->setValue(100);
|
||
|
|
m_prioritySpin->setToolTip(tr("Menor = mayor prioridad"));
|
||
|
|
|
||
|
|
optionsLayout->addWidget(m_enabledCheck);
|
||
|
|
optionsLayout->addWidget(m_matchAllCheck);
|
||
|
|
optionsLayout->addStretch();
|
||
|
|
optionsLayout->addWidget(new QLabel(tr("Prioridad:")));
|
||
|
|
optionsLayout->addWidget(m_prioritySpin);
|
||
|
|
headerLayout->addRow(optionsLayout);
|
||
|
|
|
||
|
|
mainLayout->addWidget(headerGroup);
|
||
|
|
|
||
|
|
// Conditions table
|
||
|
|
QGroupBox* condGroup = new QGroupBox(tr("Condiciones"));
|
||
|
|
QVBoxLayout* condLayout = new QVBoxLayout(condGroup);
|
||
|
|
|
||
|
|
m_conditionsTable = new QTableWidget();
|
||
|
|
m_conditionsTable->setColumnCount(5);
|
||
|
|
m_conditionsTable->setHorizontalHeaderLabels({tr("Campo"), tr("Operador"), tr("Valor"), tr("Mayúsculas"), ""});
|
||
|
|
m_conditionsTable->horizontalHeader()->setStretchLastSection(true);
|
||
|
|
m_conditionsTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
|
||
|
|
m_conditionsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||
|
|
m_conditionsTable->verticalHeader()->setVisible(false);
|
||
|
|
condLayout->addWidget(m_conditionsTable);
|
||
|
|
|
||
|
|
QHBoxLayout* condBtnLayout = new QHBoxLayout();
|
||
|
|
QPushButton* btnAddCond = new QPushButton(tr("+ Añadir condición"));
|
||
|
|
btnAddCond->setStyleSheet("QPushButton { background: #1976D2; color: white; padding: 6px 12px; border-radius: 4px; }");
|
||
|
|
connect(btnAddCond, &QPushButton::clicked, this, &RuleEditorDialog::onAddCondition);
|
||
|
|
QPushButton* btnRemCond = new QPushButton(tr("- Eliminar"));
|
||
|
|
connect(btnRemCond, &QPushButton::clicked, this, &RuleEditorDialog::onRemoveCondition);
|
||
|
|
condBtnLayout->addWidget(btnAddCond);
|
||
|
|
condBtnLayout->addWidget(btnRemCond);
|
||
|
|
condBtnLayout->addStretch();
|
||
|
|
condLayout->addLayout(condBtnLayout);
|
||
|
|
|
||
|
|
mainLayout->addWidget(condGroup, 1);
|
||
|
|
|
||
|
|
// Actions table
|
||
|
|
QGroupBox* actGroup = new QGroupBox(tr("Acciones"));
|
||
|
|
QVBoxLayout* actLayout = new QVBoxLayout(actGroup);
|
||
|
|
|
||
|
|
m_actionsTable = new QTableWidget();
|
||
|
|
m_actionsTable->setColumnCount(4);
|
||
|
|
m_actionsTable->setHorizontalHeaderLabels({tr("Tipo"), tr("Parámetro"), tr("Detalles"), ""});
|
||
|
|
m_actionsTable->horizontalHeader()->setStretchLastSection(true);
|
||
|
|
m_actionsTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||
|
|
m_actionsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||
|
|
m_actionsTable->verticalHeader()->setVisible(false);
|
||
|
|
actLayout->addWidget(m_actionsTable);
|
||
|
|
|
||
|
|
QHBoxLayout* actBtnLayout = new QHBoxLayout();
|
||
|
|
QPushButton* btnAddAct = new QPushButton(tr("+ Añadir acción"));
|
||
|
|
btnAddAct->setStyleSheet("QPushButton { background: #4CAF50; color: white; padding: 6px 12px; border-radius: 4px; }");
|
||
|
|
connect(btnAddAct, &QPushButton::clicked, this, &RuleEditorDialog::onAddAction);
|
||
|
|
QPushButton* btnRemAct = new QPushButton(tr("- Eliminar"));
|
||
|
|
connect(btnRemAct, &QPushButton::clicked, this, &RuleEditorDialog::onRemoveAction);
|
||
|
|
actBtnLayout->addWidget(btnAddAct);
|
||
|
|
actBtnLayout->addWidget(btnRemAct);
|
||
|
|
actBtnLayout->addStretch();
|
||
|
|
actLayout->addLayout(actBtnLayout);
|
||
|
|
|
||
|
|
mainLayout->addWidget(actGroup, 1);
|
||
|
|
|
||
|
|
// Buttons
|
||
|
|
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||
|
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &RuleEditorDialog::onAccept);
|
||
|
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||
|
|
mainLayout->addWidget(buttonBox);
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::loadAccounts()
|
||
|
|
{
|
||
|
|
m_accountCombo->clear();
|
||
|
|
m_accountCombo->addItem(tr("Global (todas las cuentas)"), -1);
|
||
|
|
|
||
|
|
// Get accounts via AccountService (singleton doesn't have instance(), use parent's accountService)
|
||
|
|
// For now, we'll just add the global option and let the main window handle account-specific rules
|
||
|
|
if (m_accountId >= 0) {
|
||
|
|
int idx = m_accountCombo->findData(m_accountId);
|
||
|
|
if (idx >= 0) m_accountCombo->setCurrentIndex(idx);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::populateFromRule()
|
||
|
|
{
|
||
|
|
if (!m_rule.isValid()) return;
|
||
|
|
|
||
|
|
m_nameEdit->setText(m_rule.name);
|
||
|
|
m_descEdit->setPlainText(m_rule.description);
|
||
|
|
m_enabledCheck->setChecked(m_rule.enabled);
|
||
|
|
m_matchAllCheck->setChecked(m_rule.matchAll);
|
||
|
|
m_prioritySpin->setValue(m_rule.priority);
|
||
|
|
|
||
|
|
int idx = m_accountCombo->findData(m_rule.accountId >= 0 ? m_rule.accountId : -1);
|
||
|
|
if (idx >= 0) m_accountCombo->setCurrentIndex(idx);
|
||
|
|
|
||
|
|
for (const RuleCondition& cond : m_rule.conditions) {
|
||
|
|
int row = m_conditionsTable->rowCount();
|
||
|
|
m_conditionsTable->insertRow(row);
|
||
|
|
setupConditionRow(row, cond);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (const RuleAction& act : m_rule.actions) {
|
||
|
|
int row = m_actionsTable->rowCount();
|
||
|
|
m_actionsTable->insertRow(row);
|
||
|
|
setupActionRow(row, act);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::setupConditionRow(int row, const RuleCondition& cond)
|
||
|
|
{
|
||
|
|
// Field combo
|
||
|
|
QComboBox* fieldCombo = new QComboBox();
|
||
|
|
fieldCombo->addItem(tr("De"), RuleCondition::From);
|
||
|
|
fieldCombo->addItem(tr("Para"), RuleCondition::To);
|
||
|
|
fieldCombo->addItem(tr("CC"), RuleCondition::Cc);
|
||
|
|
fieldCombo->addItem(tr("Asunto"), RuleCondition::Subject);
|
||
|
|
fieldCombo->addItem(tr("Cuerpo"), RuleCondition::Body);
|
||
|
|
fieldCombo->addItem(tr("Tiene adjuntos"), RuleCondition::HasAttachment);
|
||
|
|
fieldCombo->addItem(tr("Tamaño"), RuleCondition::Size);
|
||
|
|
fieldCombo->addItem(tr("Fecha"), RuleCondition::Date);
|
||
|
|
fieldCombo->addItem(tr("Marcado"), RuleCondition::Flagged);
|
||
|
|
fieldCombo->addItem(tr("Leído"), RuleCondition::Read);
|
||
|
|
fieldCombo->setCurrentIndex(fieldCombo->findData(cond.field));
|
||
|
|
connect(fieldCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||
|
|
[this, row](int) { onConditionFieldChanged(row); });
|
||
|
|
m_conditionsTable->setCellWidget(row, 0, fieldCombo);
|
||
|
|
|
||
|
|
// Operator combo
|
||
|
|
QComboBox* opCombo = new QComboBox();
|
||
|
|
opCombo->addItem(tr("Contiene"), RuleCondition::Contains);
|
||
|
|
opCombo->addItem(tr("No contiene"), RuleCondition::NotContains);
|
||
|
|
opCombo->addItem(tr("Es igual a"), RuleCondition::Equals);
|
||
|
|
opCombo->addItem(tr("No es igual a"), RuleCondition::NotEquals);
|
||
|
|
opCombo->addItem(tr("Empieza por"), RuleCondition::StartsWith);
|
||
|
|
opCombo->addItem(tr("Termina en"), RuleCondition::EndsWith);
|
||
|
|
opCombo->addItem(tr("Expresión regular"), RuleCondition::Regex);
|
||
|
|
opCombo->addItem(tr("Mayor que"), RuleCondition::GreaterThan);
|
||
|
|
opCombo->addItem(tr("Menor que"), RuleCondition::LessThan);
|
||
|
|
opCombo->addItem(tr("Antes de"), RuleCondition::Before);
|
||
|
|
opCombo->addItem(tr("Después de"), RuleCondition::After);
|
||
|
|
opCombo->setCurrentIndex(opCombo->findData(cond.op));
|
||
|
|
m_conditionsTable->setCellWidget(row, 1, opCombo);
|
||
|
|
|
||
|
|
// Value edit
|
||
|
|
QLineEdit* valueEdit = new QLineEdit(cond.value);
|
||
|
|
m_conditionsTable->setCellWidget(row, 2, valueEdit);
|
||
|
|
|
||
|
|
// Case sensitive checkbox
|
||
|
|
QCheckBox* caseCheck = new QCheckBox();
|
||
|
|
caseCheck->setChecked(cond.caseSensitive);
|
||
|
|
caseCheck->setStyleSheet("QCheckBox { margin-left: 50%; }");
|
||
|
|
m_conditionsTable->setCellWidget(row, 3, caseCheck);
|
||
|
|
|
||
|
|
// Remove button
|
||
|
|
QPushButton* removeBtn = new QPushButton("✕");
|
||
|
|
removeBtn->setFixedSize(24, 24);
|
||
|
|
removeBtn->setToolTip(tr("Eliminar condición"));
|
||
|
|
removeBtn->setStyleSheet("QPushButton { background: transparent; color: #d32f2f; border: none; font-weight: bold; } QPushButton:hover { background: #fdeaea; border-radius: 3px; }");
|
||
|
|
connect(removeBtn, &QPushButton::clicked, [this, row]() {
|
||
|
|
m_conditionsTable->removeRow(row);
|
||
|
|
});
|
||
|
|
m_conditionsTable->setCellWidget(row, 4, removeBtn);
|
||
|
|
|
||
|
|
onConditionFieldChanged(row);
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::onConditionFieldChanged(int row)
|
||
|
|
{
|
||
|
|
QComboBox* fieldCombo = qobject_cast<QComboBox*>(m_conditionsTable->cellWidget(row, 0));
|
||
|
|
QComboBox* opCombo = qobject_cast<QComboBox*>(m_conditionsTable->cellWidget(row, 1));
|
||
|
|
QLineEdit* valueEdit = qobject_cast<QLineEdit*>(m_conditionsTable->cellWidget(row, 2));
|
||
|
|
QCheckBox* caseCheck = qobject_cast<QCheckBox*>(m_conditionsTable->cellWidget(row, 3));
|
||
|
|
|
||
|
|
if (!fieldCombo || !opCombo) return;
|
||
|
|
|
||
|
|
RuleCondition::Field field = static_cast<RuleCondition::Field>(fieldCombo->currentData().toInt());
|
||
|
|
|
||
|
|
// Clear and repopulate operators based on field type
|
||
|
|
opCombo->clear();
|
||
|
|
|
||
|
|
bool isTextField = (field == RuleCondition::From || field == RuleCondition::To ||
|
||
|
|
field == RuleCondition::Cc || field == RuleCondition::Subject ||
|
||
|
|
field == RuleCondition::Body);
|
||
|
|
bool isBooleanField = (field == RuleCondition::HasAttachment || field == RuleCondition::Flagged || field == RuleCondition::Read);
|
||
|
|
bool isNumericField = (field == RuleCondition::Size);
|
||
|
|
bool isDateField = (field == RuleCondition::Date);
|
||
|
|
|
||
|
|
if (isTextField) {
|
||
|
|
opCombo->addItem(tr("Contiene"), RuleCondition::Contains);
|
||
|
|
opCombo->addItem(tr("No contiene"), RuleCondition::NotContains);
|
||
|
|
opCombo->addItem(tr("Es igual a"), RuleCondition::Equals);
|
||
|
|
opCombo->addItem(tr("No es igual a"), RuleCondition::NotEquals);
|
||
|
|
opCombo->addItem(tr("Empieza por"), RuleCondition::StartsWith);
|
||
|
|
opCombo->addItem(tr("Termina en"), RuleCondition::EndsWith);
|
||
|
|
opCombo->addItem(tr("Expresión regular"), RuleCondition::Regex);
|
||
|
|
valueEdit->setPlaceholderText(tr("Texto a buscar..."));
|
||
|
|
caseCheck->setVisible(true);
|
||
|
|
} else if (isBooleanField) {
|
||
|
|
opCombo->addItem(tr("Es"), RuleCondition::Equals);
|
||
|
|
opCombo->addItem(tr("No es"), RuleCondition::NotEquals);
|
||
|
|
valueEdit->setPlaceholderText("true/false");
|
||
|
|
valueEdit->setText("true");
|
||
|
|
caseCheck->setVisible(false);
|
||
|
|
} else if (isNumericField) {
|
||
|
|
opCombo->addItem(tr("Mayor que"), RuleCondition::GreaterThan);
|
||
|
|
opCombo->addItem(tr("Menor que"), RuleCondition::LessThan);
|
||
|
|
opCombo->addItem(tr("Es igual a"), RuleCondition::Equals);
|
||
|
|
valueEdit->setPlaceholderText("Tamaño en bytes");
|
||
|
|
caseCheck->setVisible(false);
|
||
|
|
} else if (isDateField) {
|
||
|
|
opCombo->addItem(tr("Antes de"), RuleCondition::Before);
|
||
|
|
opCombo->addItem(tr("Después de"), RuleCondition::After);
|
||
|
|
opCombo->addItem(tr("Es igual a"), RuleCondition::Equals);
|
||
|
|
valueEdit->setPlaceholderText("YYYY-MM-DD");
|
||
|
|
caseCheck->setVisible(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::setupActionRow(int row, const RuleAction& act)
|
||
|
|
{
|
||
|
|
// Type combo
|
||
|
|
QComboBox* typeCombo = new QComboBox();
|
||
|
|
typeCombo->addItem(tr("Mover a carpeta"), RuleAction::MoveToFolder);
|
||
|
|
typeCombo->addItem(tr("Marcar como leído/no leído"), RuleAction::MarkAsRead);
|
||
|
|
typeCombo->addItem(tr("Marcar/Desmarcar"), RuleAction::MarkAsFlagged);
|
||
|
|
typeCombo->addItem(tr("Eliminar"), RuleAction::Delete);
|
||
|
|
typeCombo->addItem(tr("Asignar categoría"), RuleAction::AssignCategory);
|
||
|
|
typeCombo->addItem(tr("Quitar categoría"), RuleAction::RemoveCategory);
|
||
|
|
typeCombo->addItem(tr("Reenviar a"), RuleAction::ForwardTo);
|
||
|
|
typeCombo->addItem(tr("Establecer prioridad"), RuleAction::SetPriority);
|
||
|
|
typeCombo->addItem(tr("Detener procesamiento"), RuleAction::StopProcessing);
|
||
|
|
typeCombo->setCurrentIndex(typeCombo->findData(act.type));
|
||
|
|
connect(typeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||
|
|
[this, row](int) { onActionTypeChanged(row); });
|
||
|
|
m_actionsTable->setCellWidget(row, 0, typeCombo);
|
||
|
|
|
||
|
|
// Parameter edit (dynamic based on type)
|
||
|
|
QWidget* paramWidget = createParameterWidget(act);
|
||
|
|
m_actionsTable->setCellWidget(row, 1, paramWidget);
|
||
|
|
|
||
|
|
// Details label
|
||
|
|
QLabel* detailsLabel = new QLabel();
|
||
|
|
detailsLabel->setStyleSheet("color: #666; font-size: 11px;");
|
||
|
|
updateActionDetails(act, detailsLabel);
|
||
|
|
m_actionsTable->setCellWidget(row, 2, detailsLabel);
|
||
|
|
|
||
|
|
// Remove button
|
||
|
|
QPushButton* removeBtn = new QPushButton("✕");
|
||
|
|
removeBtn->setFixedSize(24, 24);
|
||
|
|
removeBtn->setToolTip(tr("Eliminar acción"));
|
||
|
|
removeBtn->setStyleSheet("QPushButton { background: transparent; color: #d32f2f; border: none; font-weight: bold; } QPushButton:hover { background: #fdeaea; border-radius: 3px; }");
|
||
|
|
connect(removeBtn, &QPushButton::clicked, [this, row]() {
|
||
|
|
m_actionsTable->removeRow(row);
|
||
|
|
});
|
||
|
|
m_actionsTable->setCellWidget(row, 3, removeBtn);
|
||
|
|
}
|
||
|
|
|
||
|
|
QWidget* RuleEditorDialog::createParameterWidget(const RuleAction& act)
|
||
|
|
{
|
||
|
|
QWidget* container = new QWidget();
|
||
|
|
QHBoxLayout* layout = new QHBoxLayout(container);
|
||
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
||
|
|
|
||
|
|
switch (act.type) {
|
||
|
|
case RuleAction::MoveToFolder: {
|
||
|
|
QComboBox* folderCombo = new QComboBox();
|
||
|
|
folderCombo->addItem(tr("Seleccionar carpeta..."), -1);
|
||
|
|
// Load folders from database
|
||
|
|
QSqlDatabase db = DatabaseManager::instance().database();
|
||
|
|
QSqlQuery query(db);
|
||
|
|
query.exec("SELECT id, name FROM Folder ORDER BY name");
|
||
|
|
while (query.next()) {
|
||
|
|
folderCombo->addItem(query.value(1).toString(), query.value(0).toLongLong());
|
||
|
|
}
|
||
|
|
if (act.value.toLongLong() > 0) {
|
||
|
|
int idx = folderCombo->findData(act.value.toLongLong());
|
||
|
|
if (idx >= 0) folderCombo->setCurrentIndex(idx);
|
||
|
|
}
|
||
|
|
layout->addWidget(folderCombo, 1);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case RuleAction::MarkAsRead: {
|
||
|
|
QComboBox* combo = new QComboBox();
|
||
|
|
combo->addItem(tr("Leído"), "true");
|
||
|
|
combo->addItem(tr("No leído"), "false");
|
||
|
|
combo->setCurrentIndex(combo->findData(act.value));
|
||
|
|
layout->addWidget(combo, 1);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case RuleAction::MarkAsFlagged: {
|
||
|
|
QComboBox* combo = new QComboBox();
|
||
|
|
combo->addItem(tr("Marcado"), "true");
|
||
|
|
combo->addItem(tr("No marcado"), "false");
|
||
|
|
combo->setCurrentIndex(combo->findData(act.value));
|
||
|
|
layout->addWidget(combo, 1);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case RuleAction::AssignCategory:
|
||
|
|
case RuleAction::RemoveCategory: {
|
||
|
|
QComboBox* catCombo = new QComboBox();
|
||
|
|
catCombo->addItem(tr("Seleccionar categoría..."), -1);
|
||
|
|
QVector<Category> cats = CategoryDao::findAll();
|
||
|
|
for (const Category& cat : cats) {
|
||
|
|
catCombo->addItem(cat.name, cat.id);
|
||
|
|
}
|
||
|
|
if (act.value.toLongLong() > 0) {
|
||
|
|
int idx = catCombo->findData(act.value.toLongLong());
|
||
|
|
if (idx >= 0) catCombo->setCurrentIndex(idx);
|
||
|
|
}
|
||
|
|
layout->addWidget(catCombo, 1);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case RuleAction::ForwardTo: {
|
||
|
|
QLineEdit* edit = new QLineEdit(act.value);
|
||
|
|
edit->setPlaceholderText("email@dominio.com");
|
||
|
|
layout->addWidget(edit, 1);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case RuleAction::SetPriority: {
|
||
|
|
QComboBox* combo = new QComboBox();
|
||
|
|
combo->addItem(tr("Alta"), "high");
|
||
|
|
combo->addItem(tr("Normal"), "normal");
|
||
|
|
combo->addItem(tr("Baja"), "low");
|
||
|
|
combo->setCurrentIndex(combo->findData(act.value));
|
||
|
|
layout->addWidget(combo, 1);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case RuleAction::Delete:
|
||
|
|
case RuleAction::StopProcessing:
|
||
|
|
default: {
|
||
|
|
QLabel* label = new QLabel(tr("(sin parámetros)"));
|
||
|
|
label->setStyleSheet("color: #999; font-style: italic;");
|
||
|
|
layout->addWidget(label, 1);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return container;
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::updateActionDetails(const RuleAction& act, QLabel* label)
|
||
|
|
{
|
||
|
|
QString details;
|
||
|
|
switch (act.type) {
|
||
|
|
case RuleAction::MoveToFolder:
|
||
|
|
details = tr("Mueve el correo a la carpeta seleccionada");
|
||
|
|
break;
|
||
|
|
case RuleAction::MarkAsRead:
|
||
|
|
details = tr("Cambia el estado de lectura del correo");
|
||
|
|
break;
|
||
|
|
case RuleAction::MarkAsFlagged:
|
||
|
|
details = tr("Cambia el estado de marcado/estrella");
|
||
|
|
break;
|
||
|
|
case RuleAction::Delete:
|
||
|
|
details = tr("Elimina el correo permanentemente");
|
||
|
|
break;
|
||
|
|
case RuleAction::AssignCategory:
|
||
|
|
details = tr("Añade la categoría al correo");
|
||
|
|
break;
|
||
|
|
case RuleAction::RemoveCategory:
|
||
|
|
details = tr("Quita la categoría del correo");
|
||
|
|
break;
|
||
|
|
case RuleAction::ForwardTo:
|
||
|
|
details = tr("Reenvía el correo a la dirección indicada");
|
||
|
|
break;
|
||
|
|
case RuleAction::SetPriority:
|
||
|
|
details = tr("Marca el correo como alta prioridad (flagged)");
|
||
|
|
break;
|
||
|
|
case RuleAction::StopProcessing:
|
||
|
|
details = tr("Detiene la evaluación de más reglas para este correo");
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
label->setText(details);
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::onActionTypeChanged(int row)
|
||
|
|
{
|
||
|
|
QComboBox* typeCombo = qobject_cast<QComboBox*>(m_actionsTable->cellWidget(row, 0));
|
||
|
|
if (!typeCombo) return;
|
||
|
|
|
||
|
|
RuleAction::Type type = static_cast<RuleAction::Type>(typeCombo->currentData().toInt());
|
||
|
|
|
||
|
|
// Replace parameter widget
|
||
|
|
QWidget* oldWidget = m_actionsTable->cellWidget(row, 1);
|
||
|
|
if (oldWidget) oldWidget->deleteLater();
|
||
|
|
|
||
|
|
RuleAction act;
|
||
|
|
act.type = type;
|
||
|
|
QWidget* newWidget = createParameterWidget(act);
|
||
|
|
m_actionsTable->setCellWidget(row, 1, newWidget);
|
||
|
|
|
||
|
|
// Update details
|
||
|
|
QLabel* detailsLabel = qobject_cast<QLabel*>(m_actionsTable->cellWidget(row, 2));
|
||
|
|
if (detailsLabel) updateActionDetails(act, detailsLabel);
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::onAddCondition()
|
||
|
|
{
|
||
|
|
int row = m_conditionsTable->rowCount();
|
||
|
|
m_conditionsTable->insertRow(row);
|
||
|
|
setupConditionRow(row);
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::onRemoveCondition()
|
||
|
|
{
|
||
|
|
int row = m_conditionsTable->currentRow();
|
||
|
|
if (row >= 0) {
|
||
|
|
m_conditionsTable->removeRow(row);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::onAddAction()
|
||
|
|
{
|
||
|
|
int row = m_actionsTable->rowCount();
|
||
|
|
m_actionsTable->insertRow(row);
|
||
|
|
setupActionRow(row);
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::onRemoveAction()
|
||
|
|
{
|
||
|
|
int row = m_actionsTable->currentRow();
|
||
|
|
if (row >= 0) {
|
||
|
|
m_actionsTable->removeRow(row);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
RuleCondition RuleEditorDialog::conditionFromRow(int row) const
|
||
|
|
{
|
||
|
|
RuleCondition cond;
|
||
|
|
QComboBox* fieldCombo = qobject_cast<QComboBox*>(m_conditionsTable->cellWidget(row, 0));
|
||
|
|
QComboBox* opCombo = qobject_cast<QComboBox*>(m_conditionsTable->cellWidget(row, 1));
|
||
|
|
QLineEdit* valueEdit = qobject_cast<QLineEdit*>(m_conditionsTable->cellWidget(row, 2));
|
||
|
|
QCheckBox* caseCheck = qobject_cast<QCheckBox*>(m_conditionsTable->cellWidget(row, 3));
|
||
|
|
|
||
|
|
if (fieldCombo) cond.field = static_cast<RuleCondition::Field>(fieldCombo->currentData().toInt());
|
||
|
|
if (opCombo) cond.op = static_cast<RuleCondition::Operator>(opCombo->currentData().toInt());
|
||
|
|
if (valueEdit) cond.value = valueEdit->text();
|
||
|
|
if (caseCheck) cond.caseSensitive = caseCheck->isChecked();
|
||
|
|
|
||
|
|
return cond;
|
||
|
|
}
|
||
|
|
|
||
|
|
RuleAction RuleEditorDialog::actionFromRow(int row) const
|
||
|
|
{
|
||
|
|
RuleAction act;
|
||
|
|
QComboBox* typeCombo = qobject_cast<QComboBox*>(m_actionsTable->cellWidget(row, 0));
|
||
|
|
QWidget* paramWidget = m_actionsTable->cellWidget(row, 1);
|
||
|
|
|
||
|
|
if (typeCombo) act.type = static_cast<RuleAction::Type>(typeCombo->currentData().toInt());
|
||
|
|
|
||
|
|
if (!paramWidget) return act;
|
||
|
|
|
||
|
|
// Extract value based on action type
|
||
|
|
if (act.type == RuleAction::MoveToFolder ||
|
||
|
|
act.type == RuleAction::AssignCategory ||
|
||
|
|
act.type == RuleAction::RemoveCategory) {
|
||
|
|
QComboBox* combo = paramWidget->findChild<QComboBox*>();
|
||
|
|
if (combo && combo->currentData().toLongLong() > 0) {
|
||
|
|
act.value = QString::number(combo->currentData().toLongLong());
|
||
|
|
}
|
||
|
|
} else if (act.type == RuleAction::MarkAsRead ||
|
||
|
|
act.type == RuleAction::MarkAsFlagged ||
|
||
|
|
act.type == RuleAction::SetPriority) {
|
||
|
|
QComboBox* combo = paramWidget->findChild<QComboBox*>();
|
||
|
|
if (combo) act.value = combo->currentData().toString();
|
||
|
|
} else if (act.type == RuleAction::ForwardTo) {
|
||
|
|
QLineEdit* edit = paramWidget->findChild<QLineEdit*>();
|
||
|
|
if (edit) act.value = edit->text();
|
||
|
|
}
|
||
|
|
|
||
|
|
return act;
|
||
|
|
}
|
||
|
|
|
||
|
|
void RuleEditorDialog::onAccept()
|
||
|
|
{
|
||
|
|
if (m_nameEdit->text().trimmed().isEmpty()) {
|
||
|
|
QMessageBox::warning(this, tr("Error"), tr("El nombre de la regla es obligatorio."));
|
||
|
|
m_nameEdit->setFocus();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_rule.name = m_nameEdit->text().trimmed();
|
||
|
|
m_rule.description = m_descEdit->toPlainText().trimmed();
|
||
|
|
m_rule.enabled = m_enabledCheck->isChecked();
|
||
|
|
m_rule.matchAll = m_matchAllCheck->isChecked();
|
||
|
|
m_rule.priority = m_prioritySpin->value();
|
||
|
|
m_rule.accountId = m_accountCombo->currentData().toLongLong();
|
||
|
|
if (m_rule.accountId < 0) m_rule.accountId = -1;
|
||
|
|
|
||
|
|
m_rule.conditions.clear();
|
||
|
|
for (int i = 0; i < m_conditionsTable->rowCount(); ++i) {
|
||
|
|
m_rule.conditions.append(conditionFromRow(i));
|
||
|
|
}
|
||
|
|
|
||
|
|
m_rule.actions.clear();
|
||
|
|
for (int i = 0; i < m_actionsTable->rowCount(); ++i) {
|
||
|
|
m_rule.actions.append(actionFromRow(i));
|
||
|
|
}
|
||
|
|
|
||
|
|
m_rule.updatedAt = QDateTime::currentDateTime();
|
||
|
|
|
||
|
|
if (m_rule.isValid()) {
|
||
|
|
if (RuleDao::update(m_rule)) {
|
||
|
|
emit ruleSaved(m_rule);
|
||
|
|
accept();
|
||
|
|
} else {
|
||
|
|
QMessageBox::critical(this, tr("Error"), tr("No se pudo actualizar la regla."));
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (RuleDao::insert(m_rule)) {
|
||
|
|
emit ruleSaved(m_rule);
|
||
|
|
accept();
|
||
|
|
} else {
|
||
|
|
QMessageBox::critical(this, tr("Error"), tr("No se pudo crear la regla."));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|