File indexing completed on 2024-06-16 04:47:29

0001 /***************************************************************************
0002  * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr
0003  * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  ***************************************************************************/
0006 /** @file
0007  * A skrooge plugin to track transactions.
0008  *
0009  * @author Stephane MANKOWSKI
0010  */
0011 #include "skgpayeepluginwidget.h"
0012 
0013 #include <qaction.h>
0014 
0015 #include <qdom.h>
0016 #include <qevent.h>
0017 
0018 #include "skgcategoryobject.h"
0019 #include "skgdocumentbank.h"
0020 #include "skgmainpanel.h"
0021 #include "skgobjectmodel.h"
0022 #include "skgpayeeobject.h"
0023 #include "skgtraces.h"
0024 #include "skgtransactionmng.h"
0025 
0026 SKGPayeePluginWidget::SKGPayeePluginWidget(QWidget* iParent, SKGDocument* iDocument)
0027     : SKGTabPage(iParent, iDocument)
0028 {
0029     SKGTRACEINFUNC(1)
0030     if (iDocument == nullptr) {
0031         return;
0032     }
0033 
0034     ui.setupUi(this);
0035 
0036     // Set show widget
0037     ui.kView->getShowWidget()->addGroupedItem(QStringLiteral("all"), i18n("All"), QLatin1String(""), QLatin1String(""), QLatin1String(""), Qt::META + Qt::Key_A);
0038     ui.kView->getShowWidget()->addGroupedItem(QStringLiteral("opened"), i18n("Opened"), QStringLiteral("vcs-normal"), QStringLiteral("t_close='N'"), QLatin1String(""), Qt::META + Qt::Key_O);
0039     ui.kView->getShowWidget()->addGroupedItem(QStringLiteral("closed"), i18n("Closed"), QStringLiteral("vcs-conflicting"), QStringLiteral("t_close='Y'"), QLatin1String(""), Qt::META + Qt::Key_C);
0040     ui.kView->getShowWidget()->addGroupedItem(QStringLiteral("highlighted"), i18n("Highlighted only"), QStringLiteral("bookmarks"), QStringLiteral("t_bookmarked='Y'"), QLatin1String(""), Qt::META + Qt::Key_H);
0041     ui.kView->getShowWidget()->addGroupedItem(QStringLiteral("income"), i18n("Income"), QStringLiteral("list-add"), QStringLiteral("f_CURRENTAMOUNT>=0"), QLatin1String(""), Qt::META + Qt::Key_Plus);
0042     ui.kView->getShowWidget()->addGroupedItem(QStringLiteral("expenditure"), i18n("Expenditure"), QStringLiteral("list-remove"), QStringLiteral("f_CURRENTAMOUNT<=0"), QLatin1String(""), Qt::META + Qt::Key_Minus);
0043     ui.kView->getShowWidget()->setDefaultState(QStringLiteral("all"));
0044 
0045 
0046     ui.kView->getShowWidget()->setDefaultState(QStringLiteral("all"));
0047 
0048     ui.kNameLbl->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_name"))));
0049     ui.kAddressLabel->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_address"))));
0050     ui.kCategoryLabel->setText(i18n("%1:", iDocument->getDisplay(QStringLiteral("t_CATEGORY"))));
0051 
0052     ui.kAddButton->setIcon(SKGServices::fromTheme(QStringLiteral("list-add")));
0053     ui.kModifyButton->setIcon(SKGServices::fromTheme(QStringLiteral("dialog-ok")));
0054     ui.kDeleteUnusedButton->setIcon(SKGServices::fromTheme(QStringLiteral("edit-delete")));
0055 
0056     ui.kView->setModel(new SKGObjectModel(qobject_cast<SKGDocumentBank*>(getDocument()), QStringLiteral("v_payee_display"), QStringLiteral("1=0"), this, QLatin1String(""), false));
0057     ui.kView->getView()->resizeColumnToContents(0);
0058 
0059     connect(getDocument(), &SKGDocument::tableModified, this, &SKGPayeePluginWidget::dataModified, Qt::QueuedConnection);
0060     connect(ui.kView->getView(), &SKGTreeView::clickEmptyArea, this, &SKGPayeePluginWidget::cleanEditor);
0061     connect(ui.kView->getView(), &SKGTreeView::doubleClicked, SKGMainPanel::getMainPanel()->getGlobalAction(QStringLiteral("open")).data(), &QAction::trigger);
0062     connect(ui.kView->getView(), &SKGTreeView::selectionChangedDelayed, this, [ = ] {this->onSelectionChanged();});
0063 
0064     connect(ui.kAddButton, &QPushButton::clicked, this, &SKGPayeePluginWidget::onAddPayee);
0065     connect(ui.kModifyButton, &QPushButton::clicked, this, &SKGPayeePluginWidget::onModifyPayee);
0066     connect(ui.kNameInput, &QLineEdit::textChanged, this, &SKGPayeePluginWidget::onEditorModified);
0067     connect(ui.kDeleteUnusedButton, &QPushButton::clicked, this, &SKGPayeePluginWidget::onDeleteUnused);
0068 
0069     // Set Event filters to catch CTRL+ENTER or SHIFT+ENTER
0070     this->installEventFilter(this);
0071 
0072     dataModified(QLatin1String(""), 0);
0073 }
0074 
0075 SKGPayeePluginWidget::~SKGPayeePluginWidget()
0076 {
0077     SKGTRACEINFUNC(1)
0078 }
0079 
0080 bool SKGPayeePluginWidget::eventFilter(QObject* iObject, QEvent* iEvent)
0081 {
0082     if ((iEvent != nullptr) && iEvent->type() == QEvent::KeyPress) {
0083         auto* keyEvent = dynamic_cast<QKeyEvent*>(iEvent);
0084         if (keyEvent && (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && iObject == this) {
0085             if ((QApplication::keyboardModifiers() & Qt::ControlModifier) != 0u && ui.kAddButton->isEnabled()) {
0086                 ui.kAddButton->click();
0087             } else if ((QApplication::keyboardModifiers() &Qt::ShiftModifier) != 0u && ui.kModifyButton->isEnabled()) {
0088                 ui.kModifyButton->click();
0089             }
0090         }
0091     }
0092 
0093     return SKGTabPage::eventFilter(iObject, iEvent);
0094 }
0095 
0096 void SKGPayeePluginWidget::onSelectionChanged()
0097 {
0098     SKGTRACEINFUNC(10)
0099 
0100     int nbSelect = ui.kView->getView()->getNbSelectedObjects();
0101     if (nbSelect == 1) {
0102         SKGPayeeObject obj(ui.kView->getView()->getFirstSelectedObject());
0103 
0104         ui.kNameInput->setText(obj.getName());
0105         ui.kAddressEdit->setText(obj.getAddress());
0106         ui.kCategoryEdit->setText(obj.getAttribute(QStringLiteral("t_CATEGORY")));
0107     } else if (nbSelect > 1) {
0108         ui.kNameInput->setText(NOUPDATE);
0109         ui.kAddressEdit->setText(NOUPDATE);
0110         ui.kCategoryEdit->setText(NOUPDATE);
0111     }
0112 
0113     onEditorModified();
0114     Q_EMIT selectionChanged();
0115 }
0116 
0117 QString SKGPayeePluginWidget::getState()
0118 {
0119     SKGTRACEINFUNC(10)
0120     QDomDocument doc(QStringLiteral("SKGML"));
0121     QDomElement root = doc.createElement(QStringLiteral("parameters"));
0122     doc.appendChild(root);
0123     root.setAttribute(QStringLiteral("view"), ui.kView->getState());
0124     return doc.toString();
0125 }
0126 
0127 void SKGPayeePluginWidget::setState(const QString& iState)
0128 {
0129     SKGTRACEINFUNC(10)
0130     QDomDocument doc(QStringLiteral("SKGML"));
0131     doc.setContent(iState);
0132     QDomElement root = doc.documentElement();
0133 
0134     ui.kView->setFilter(SKGServices::fromTheme(root.attribute(QStringLiteral("title_icon"))), root.attribute(QStringLiteral("title")), root.attribute(QStringLiteral("whereClause")));
0135     ui.kView->setState(root.attribute(QStringLiteral("view")));
0136 }
0137 
0138 QString SKGPayeePluginWidget::getDefaultStateAttribute()
0139 {
0140     return QStringLiteral("SKGPAYEE_DEFAULT_PARAMETERS");
0141 }
0142 
0143 QWidget* SKGPayeePluginWidget::mainWidget()
0144 {
0145     return ui.kView->getView();
0146 }
0147 
0148 void SKGPayeePluginWidget::onEditorModified()
0149 {
0150     _SKGTRACEINFUNC(10)
0151     int nb = getNbSelectedObjects();
0152     ui.kModifyButton->setEnabled(!ui.kNameInput->text().isEmpty() && nb >= 1);
0153     ui.kAddButton->setEnabled(!ui.kNameInput->text().isEmpty() &&
0154                               !ui.kNameInput->text().startsWith(QLatin1Char('=')));
0155 }
0156 
0157 void SKGPayeePluginWidget::dataModified(const QString& iTableName, int iIdTransaction, bool iLightTransaction)
0158 {
0159     SKGTRACEINFUNC(10)
0160     Q_UNUSED(iIdTransaction)
0161 
0162     if (!iLightTransaction) {
0163         if (iTableName == QStringLiteral("payee") || iTableName.isEmpty()) {
0164             // Set completions
0165             SKGMainPanel::fillWithDistinctValue(QList<QWidget*>() << ui.kNameInput, getDocument(), QStringLiteral("payee"), QStringLiteral("t_name"), QLatin1String(""), true);
0166             SKGMainPanel::fillWithDistinctValue(QList<QWidget*>() << ui.kAddressEdit, getDocument(), QStringLiteral("payee"), QStringLiteral("t_address"), QLatin1String(""), true);
0167             SKGMainPanel::fillWithDistinctValue(QList<QWidget*>() << ui.kCategoryEdit, getDocument(), QStringLiteral("category"), QStringLiteral("t_fullname"), QLatin1String(""));
0168         }
0169     }
0170 }
0171 
0172 void SKGPayeePluginWidget::onAddPayee()
0173 {
0174     SKGError err;
0175     _SKGTRACEINFUNCRC(10, err)
0176 
0177     QString name = ui.kNameInput->text();
0178     SKGPayeeObject payee;
0179     {
0180         SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Payee creation '%1'", name), err)
0181 
0182         IFOKDO(err, SKGPayeeObject::createPayee(qobject_cast<SKGDocumentBank*>(getDocument()), name, payee))
0183         IFOKDO(err, payee.setAddress(ui.kAddressEdit->text()))
0184         SKGCategoryObject cat;
0185         QString catName = ui.kCategoryEdit->text().trimmed();
0186         if (!err &&  catName != NOUPDATE) {
0187             err = SKGCategoryObject::createPathCategory(qobject_cast<SKGDocumentBank*>(getDocument()), catName, cat, true);
0188         }
0189         IFOKDO(err, payee.setCategory(cat))
0190 
0191         IFOKDO(err, payee.save())
0192 
0193         // Send message
0194         IFOKDO(err, payee.getDocument()->sendMessage(i18nc("An information message", "The payee '%1' has been added", payee.getDisplayName()), SKGDocument::Hidden))
0195     }
0196     // status bar
0197     IFOK(err) {
0198         err = SKGError(0, i18nc("Successful message after an user action", "Payee '%1' created", name));
0199         ui.kView->getView()->selectObject(payee.getUniqueID());
0200     } else {
0201         err.addError(ERR_FAIL, i18nc("Error message", "Payee creation failed"));
0202     }
0203 
0204     // Display error
0205     SKGMainPanel::displayErrorMessage(err, true);
0206 }
0207 
0208 void SKGPayeePluginWidget::onModifyPayee()
0209 {
0210     SKGError err;
0211     _SKGTRACEINFUNCRC(10, err)
0212 
0213     // Get Selection
0214     SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects();
0215 
0216     int nb = selection.count();
0217 
0218     {
0219         SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Payee update"), err, nb)
0220         auto name = ui.kNameInput->text();
0221         if (name != NOUPDATE && !name.startsWith(QLatin1String("="))) {
0222             // Is this name already existing?
0223             bool messageSent = false;
0224             SKGPayeeObject p(getDocument());
0225             p.setName(name);
0226             IFOK(p.load()) {
0227                 if (selection.indexOf(p) == -1) {
0228                     // We will have to merge with the existing payee
0229                     selection.insert(0, p);
0230                     nb++;
0231 
0232                     getDocument()->sendMessage(i18nc("Information message", "You tried to modify names of selected payees to an existing payee. Payees have been merged."));
0233                     messageSent = true;
0234                 }
0235             }
0236 
0237             // Is it a massive modification of payees to merge them ?
0238             if (nb > 1) {
0239                 if (!messageSent) {
0240                     getDocument()->sendMessage(i18nc("Information message", "You tried to modify all names of selected payees. Payees have been merged."));
0241                 }
0242 
0243                 // Do the merge
0244                 SKGPayeeObject payeeObj1(selection[0]);
0245                 for (int i = 1; !err && i < nb; ++i) {
0246                     SKGPayeeObject payeeObj(selection.at(i));
0247 
0248                     // Send message
0249                     IFOKDO(err, payeeObj.getDocument()->sendMessage(i18nc("An information message", "The payee '%1' has been merged with payee '%2'", payeeObj1.getDisplayName(), payeeObj.getDisplayName()), SKGDocument::Hidden))
0250 
0251                     err = payeeObj1.merge(payeeObj);
0252                 }
0253 
0254                 // Change selection for the rest of the transaction
0255                 selection.clear();
0256                 selection.push_back(payeeObj1);
0257                 nb = 1;
0258             }
0259         }
0260 
0261         for (int i = 0; !err && i < nb; ++i) {
0262             // Modification of object
0263             SKGPayeeObject payee(selection.at(i));
0264             err = payee.setName(name);
0265             QString address = ui.kAddressEdit->text();
0266             if (address != NOUPDATE) {
0267                 IFOKDO(err, payee.setAddress(address))
0268             }
0269             SKGCategoryObject cat;
0270             QString catName = ui.kCategoryEdit->text().trimmed();
0271             if (!err &&  catName != NOUPDATE) {
0272                 err = SKGCategoryObject::createPathCategory(qobject_cast<SKGDocumentBank*>(getDocument()), catName, cat, true);
0273                 IFOKDO(err, payee.setCategory(cat))
0274             }
0275             IFOKDO(err, payee.save())
0276 
0277             // Send message
0278             IFOKDO(err, payee.getDocument()->sendMessage(i18nc("An information message", "The payee '%1' has been updated", payee.getDisplayName()), SKGDocument::Hidden))
0279         }
0280     }
0281 
0282     // status bar
0283     IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Payee updated")))
0284     else {
0285         err.addError(ERR_FAIL, i18nc("Error message", "Payee update failed"));
0286     }
0287 
0288     // Display error
0289     SKGMainPanel::displayErrorMessage(err, true);
0290 
0291     // Set focus on table
0292     ui.kView->getView()->setFocus();
0293 }
0294 
0295 void SKGPayeePluginWidget::cleanEditor()
0296 {
0297     if (getNbSelectedObjects() == 0) {
0298         ui.kNameInput->setText(QLatin1String(""));
0299         ui.kAddressEdit->setText(QLatin1String(""));
0300     }
0301 }
0302 
0303 void SKGPayeePluginWidget::activateEditor()
0304 {
0305     ui.kNameInput->setFocus();
0306 }
0307 
0308 bool SKGPayeePluginWidget::isEditor()
0309 {
0310     return true;
0311 }
0312 
0313 void SKGPayeePluginWidget::onDeleteUnused()
0314 {
0315     QAction* act = SKGMainPanel::getMainPanel()->getGlobalAction(QStringLiteral("clean_delete_unused_payees"));
0316     if (act != nullptr) {
0317         act->trigger();
0318     }
0319 }