File indexing completed on 2024-05-19 05:06:50

0001 /*
0002     SPDX-FileCopyrightText: 2004-2020 Thomas Baumgart <tbaumgart@kde.org>
0003     SPDX-FileCopyrightText: 2009-2010 Alvaro Soliverez <asoliverez@gmail.com>
0004     SPDX-FileCopyrightText: 2017-2018 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "kcurrencyeditdlg.h"
0009 
0010 #include <locale.h>
0011 
0012 // ----------------------------------------------------------------------------
0013 // QT Includes
0014 
0015 #include <QPixmap>
0016 #include <QBitmap>
0017 #include <QList>
0018 #include <QTreeWidget>
0019 #include <QStyledItemDelegate>
0020 #include <QIcon>
0021 #include <QPushButton>
0022 #include <QBitArray>
0023 #include <QInputDialog>
0024 #include <QMenu>
0025 
0026 // ----------------------------------------------------------------------------
0027 // KDE Includes
0028 
0029 #include <KTreeWidgetSearchLineWidget>
0030 #include <KMessageBox>
0031 #include <KLocalizedString>
0032 
0033 // ----------------------------------------------------------------------------
0034 // Project Includes
0035 
0036 #include "ui_kcurrencyeditdlg.h"
0037 
0038 #include "mymoneyexception.h"
0039 #include "mymoneysecurity.h"
0040 #include "mymoneyfile.h"
0041 #include "mymoneyprice.h"
0042 #include "kavailablecurrencydlg.h"
0043 #include "kcurrencyeditordlg.h"
0044 #include "kmymoneyutils.h"
0045 #include "icons/icons.h"
0046 #include "storageenums.h"
0047 #include "mymoneyenums.h"
0048 
0049 using namespace Icons;
0050 
0051 // duplicated eMenu namespace from menuenums.h for consistency
0052 // there shouldn't be any clash, because we don't need menuenums.h here
0053 namespace eMenu {
0054 enum class Action {
0055     // *************
0056     // The currency menu
0057     // *************
0058     NewCurrency, RenameCurrency, DeleteCurrency,
0059     SetBaseCurrency,
0060 };
0061 inline qHashSeedType qHash(const Action key, qHashSeedType seed)
0062 {
0063     return ::qHash(static_cast<uint>(key), seed);
0064 }
0065 }
0066 
0067 // this delegate is needed to disable editing the currency id (column 1)
0068 // since QTreeWidgetItem has only one set of flags for the whole row
0069 // the column editable property couldn't be set in an easier way
0070 class KCurrencyEditDelegate : public QStyledItemDelegate
0071 {
0072 public:
0073     explicit KCurrencyEditDelegate(QObject *parent = 0);
0074 
0075 protected:
0076     QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const final override;
0077 };
0078 
0079 KCurrencyEditDelegate::KCurrencyEditDelegate(QObject* parent): QStyledItemDelegate(parent)
0080 {
0081 }
0082 
0083 QWidget *KCurrencyEditDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
0084 {
0085     if (index.column() == 1)
0086         return 0;
0087     return QStyledItemDelegate::createEditor(parent, option, index);
0088 }
0089 
0090 class KCurrencyEditDlgPrivate
0091 {
0092     Q_DISABLE_COPY(KCurrencyEditDlgPrivate)
0093     Q_DECLARE_PUBLIC(KCurrencyEditDlg)
0094 
0095 public:
0096     explicit KCurrencyEditDlgPrivate(KCurrencyEditDlg *qq) :
0097         q_ptr(qq),
0098         ui(new Ui::KCurrencyEditDlg),
0099         m_availableCurrencyDlg(nullptr),
0100         m_currencyEditorDlg(nullptr),
0101         m_searchWidget(nullptr),
0102         m_inLoading(false)
0103     {
0104     }
0105 
0106     ~KCurrencyEditDlgPrivate()
0107     {
0108         delete ui;
0109     }
0110 
0111     enum removalModeE :int { RemoveSelected, RemoveUnused };
0112 
0113     void removeCurrency(const removalModeE& mode)
0114     {
0115         Q_Q(KCurrencyEditDlg);
0116         auto file = MyMoneyFile::instance();
0117         MyMoneyFileTransaction ft;
0118         QBitArray skip((int)eStorage::Reference::Count);
0119         skip.fill(false);                                 // check reference to all...
0120         skip.setBit((int)eStorage::Reference::Price);      // ...except price
0121 
0122         QTreeWidgetItemIterator it (ui->m_currencyList);  // iterate over whole tree
0123         if (mode == RemoveUnused) {
0124             while (*it) {
0125                 MyMoneySecurity currency = (*it)->data(0, Qt::UserRole).value<MyMoneySecurity>();
0126                 if (file->baseCurrency() != currency && !file->isReferenced(currency, skip))
0127                     KMyMoneyUtils::deleteSecurity(currency, q);
0128                 ++it;
0129             }
0130         } else if (mode == RemoveSelected) {
0131             const QList<QTreeWidgetItem*> currencyRows = ui->m_currencyList->selectedItems();
0132             for (const auto& currencyRow : currencyRows) {
0133                 MyMoneySecurity currency = currencyRow->data(0, Qt::UserRole).value<MyMoneySecurity>();
0134                 if (file->baseCurrency() != currency && !file->isReferenced(currency, skip))
0135                     KMyMoneyUtils::deleteSecurity(currency, q);
0136             }
0137         }
0138         ft.commit();
0139         ui->m_removeUnusedCurrencyButton->setDisabled(file->currencyList().count() <= 1);
0140     }
0141 
0142     void setBaseCurrency(const MyMoneySecurity& cur)
0143     {
0144         Q_Q(KCurrencyEditDlg);
0145         if (!cur.id().isEmpty()) {
0146             if (cur.id() != MyMoneyFile::instance()->baseCurrency().id()) {
0147                 MyMoneyFileTransaction ft;
0148                 try {
0149                     MyMoneyFile::instance()->setBaseCurrency(cur);
0150                     ft.commit();
0151                 } catch (const MyMoneyException &e) {
0152                     KMessageBox::error(q, i18n("Cannot set %1 as base currency: %2", cur.name(), QString::fromLatin1(e.what())), i18n("Set base currency"));
0153                 }
0154             }
0155         }
0156     }
0157 
0158     void updateCurrency(const QString &currencyId, const QString& currencyName, const QString& currencyTradingSymbol)
0159     {
0160         Q_Q(KCurrencyEditDlg);
0161         const auto file = MyMoneyFile::instance();
0162         try {
0163             if (currencyName != m_currentCurrency.name() || currencyTradingSymbol != m_currentCurrency.tradingSymbol()) {
0164                 MyMoneySecurity currency = file->currency(currencyId);
0165                 currency.setName(currencyName);
0166                 currency.setTradingSymbol(currencyTradingSymbol);
0167                 MyMoneyFileTransaction ft;
0168                 try {
0169                     file->modifyCurrency(currency);
0170                     m_currentCurrency = currency;
0171                     ft.commit();
0172                 } catch (const MyMoneyException &e) {
0173                     KMessageBox::error(q, i18n("Cannot update currency. %1", QString::fromLatin1(e.what())), i18n("Update currency"));
0174                 }
0175             }
0176         } catch (const MyMoneyException &e) {
0177             KMessageBox::error(q, i18n("Cannot update currency. %1", QString::fromLatin1(e.what())), i18n("Update currency"));
0178         }
0179     }
0180 
0181     /**
0182      * Edit or create a currency
0183      *
0184      * @param currency reference to currency object
0185      *
0186      * @returns @c true in case the operation was successful @c false otherwise
0187      * @note @a currency will be updated with the modified values
0188      */
0189     bool editCurrency(MyMoneySecurity& currency)
0190     {
0191         QScopedPointer<KCurrencyEditorDlg> currencyEditorDlg(new KCurrencyEditorDlg(currency, q_ptr));
0192         bool rc = true;
0193         do {
0194             if (currencyEditorDlg->exec() != QDialog::Rejected) {
0195                 auto file = MyMoneyFile::instance();
0196                 MyMoneyFileTransaction ft;
0197                 try {
0198                     if (currency.id().isEmpty()) {
0199                         file->addCurrency(currencyEditorDlg->currency());
0200                     } else {
0201                         file->modifyCurrency(currencyEditorDlg->currency());
0202                     }
0203                     ft.commit();
0204                     // if the modification worked, then we copy the data
0205                     // to inform caller
0206                     currency = currencyEditorDlg->currency();
0207 
0208                 } catch (const MyMoneyException &e) {
0209                     if (currency.id().isEmpty()) {
0210                         KMessageBox::error(q_ptr, i18n("Cannot create new currency. %1", QString::fromLatin1(e.what())), i18n("New currency"));
0211                     } else {
0212                         KMessageBox::error(q_ptr, i18n("Cannot modify currency. %1", QString::fromLatin1(e.what())), i18n("Edit currency"));
0213                     }
0214                 }
0215             } else {
0216                 rc = false;   // aborted by user
0217             }
0218         } while(false);
0219 
0220         return rc;
0221     }
0222 
0223     KCurrencyEditDlg      *q_ptr;
0224     Ui::KCurrencyEditDlg  *ui;
0225 
0226     KAvailableCurrencyDlg *m_availableCurrencyDlg;
0227     KCurrencyEditorDlg    *m_currencyEditorDlg;
0228     MyMoneySecurity        m_currentCurrency;
0229     /**
0230       * Search widget for the list
0231       */
0232     KTreeWidgetSearchLineWidget*    m_searchWidget;
0233     bool                   m_inLoading;
0234 };
0235 
0236 KCurrencyEditDlg::KCurrencyEditDlg(QWidget *parent) :
0237     QDialog(parent),
0238     d_ptr(new KCurrencyEditDlgPrivate(this))
0239 {
0240     Q_D(KCurrencyEditDlg);
0241     d->ui->setupUi(this);
0242     d->m_searchWidget = new KTreeWidgetSearchLineWidget(this, d->ui->m_currencyList);
0243     d->m_searchWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
0244     d->m_searchWidget->setFocus();
0245     d->ui->verticalLayout->insertWidget(0, d->m_searchWidget);
0246     d->ui->m_currencyList->setItemDelegate(new KCurrencyEditDelegate(d->ui->m_currencyList));
0247     d->ui->m_closeButton->setIcon(Icons::get(Icon::DialogClose));
0248     d->ui->m_newCurrencyButton->setIcon(Icons::get(Icon::DocumentNew));
0249     d->ui->m_editCurrencyButton->setIcon(Icons::get(Icon::DocumentEdit));
0250     d->ui->m_selectBaseCurrencyButton->setIcon(Icons::get(Icon::KMyMoney));
0251 
0252     connect(d->ui->m_currencyList, &QWidget::customContextMenuRequested, this, &KCurrencyEditDlg::slotShowCurrencyMenu);
0253     connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, this, &KCurrencyEditDlg::slotLoadCurrencies);
0254     connect(d->ui->m_currencyList, &QTreeWidget::itemChanged, this, static_cast<void (KCurrencyEditDlg::*)(QTreeWidgetItem *, int)>(&KCurrencyEditDlg::slotUpdateCurrency));
0255     connect(d->ui->m_currencyList, &QTreeWidget::itemSelectionChanged, this, &KCurrencyEditDlg::slotItemSelectionChanged);
0256 
0257     connect(d->ui->m_selectBaseCurrencyButton, &QAbstractButton::clicked, this, &KCurrencyEditDlg::slotSelectBaseCurrency);
0258     connect(d->ui->m_addCurrencyButton, &QAbstractButton::clicked, this, &KCurrencyEditDlg::slotAddCurrency);
0259     connect(d->ui->m_newCurrencyButton, &QAbstractButton::clicked, this, &KCurrencyEditDlg::slotNewCurrency);
0260     connect(d->ui->m_removeCurrencyButton, &QAbstractButton::clicked, this, &KCurrencyEditDlg::slotRemoveCurrency);
0261     connect(d->ui->m_editCurrencyButton, &QAbstractButton::clicked, this, &KCurrencyEditDlg::slotEditCurrency);
0262     connect(d->ui->m_removeUnusedCurrencyButton, &QAbstractButton::clicked, this, &KCurrencyEditDlg::slotRemoveUnusedCurrency);
0263 
0264     QMetaObject::invokeMethod(this, "finishCtor", Qt::QueuedConnection);
0265 }
0266 
0267 void KCurrencyEditDlg::finishCtor()
0268 {
0269     Q_D(KCurrencyEditDlg);
0270     slotLoadCurrencies();
0271 
0272     //resize the column widths
0273     for (auto i = 0; i < 3; ++i)
0274         d->ui->m_currencyList->resizeColumnToContents(i);
0275 
0276     if (!d->m_currentCurrency.id().isEmpty()) {
0277         QTreeWidgetItemIterator it(d->ui->m_currencyList);
0278         QTreeWidgetItem* q;
0279         while ((q = *it) != 0) {
0280             if (q->text(1) == d->m_currentCurrency.id()) {
0281                 d->ui->m_currencyList->scrollToItem(q);
0282                 break;
0283             }
0284             ++it;
0285         }
0286     }
0287 }
0288 
0289 KCurrencyEditDlg::~KCurrencyEditDlg()
0290 {
0291     Q_D(KCurrencyEditDlg);
0292     delete d;
0293 }
0294 
0295 void KCurrencyEditDlg::slotLoadCurrencies()
0296 {
0297     const QSet<QString> metalSymbols { "XAU", "XPD", "XPT", "XAG" };
0298 
0299     Q_D(KCurrencyEditDlg);
0300 
0301     // catch recursive calls and avoid them
0302     if (d->m_inLoading)
0303         return;
0304     d->m_inLoading = true;
0305 
0306     disconnect(d->ui->m_currencyList, &QTreeWidget::currentItemChanged, this, static_cast<void (KCurrencyEditDlg::*)(QTreeWidgetItem *, QTreeWidgetItem *)>(&KCurrencyEditDlg::slotSelectCurrency));
0307     disconnect(d->ui->m_currencyList, &QTreeWidget::itemChanged, this, static_cast<void (KCurrencyEditDlg::*)(QTreeWidgetItem *, int)>(&KCurrencyEditDlg::slotUpdateCurrency));
0308 
0309     QList<MyMoneySecurity> list = MyMoneyFile::instance()->currencyList();
0310     QList<MyMoneySecurity>::ConstIterator it;
0311     QTreeWidgetItem *first = 0;
0312 
0313     // sort the currencies ...
0314     // ... and make sure a few precious metals are at the end
0315     std::sort(list.begin(), list.end(),
0316               [=] (const MyMoneySecurity& c1, const MyMoneySecurity& c2)
0317     {
0318         const bool c1Metal = c1.tradingSymbol().startsWith(QLatin1Char('X')) && metalSymbols.contains(c1.tradingSymbol());
0319         const bool c2Metal = c2.tradingSymbol().startsWith(QLatin1Char('X')) && metalSymbols.contains(c2.tradingSymbol());
0320         if (c1Metal ^ c2Metal)
0321             return c2Metal;
0322 
0323         return c1.name().compare(c2.name()) < 0;
0324     });
0325 
0326     QString localCurrency(localeconv()->int_curr_symbol);
0327     localCurrency.truncate(3);
0328 
0329     QString baseCurrency;
0330     try {
0331         baseCurrency = MyMoneyFile::instance()->baseCurrency().id();
0332     } catch (const MyMoneyException &e) {
0333         qDebug("%s", e.what());
0334     }
0335 
0336     // construct a transparent 16x16 pixmap
0337     QPixmap empty(16, 16);
0338     QBitmap mask(16, 16);
0339     mask.clear();
0340     empty.setMask(mask);
0341 
0342     d->ui->m_currencyList->setSortingEnabled(false);
0343     d->ui->m_currencyList->clear();
0344     for (it = list.constBegin(); it != list.constEnd(); ++it) {
0345         QTreeWidgetItem *p = new QTreeWidgetItem(d->ui->m_currencyList);
0346         p->setText(0, (*it).name());
0347         p->setData(0, Qt::UserRole, QVariant::fromValue(*it));
0348         p->setFlags(p->flags() | Qt::ItemIsEditable);
0349         p->setText(1, (*it).id());
0350         // fix the ATS problem
0351         QString symbol = (*it).tradingSymbol();
0352         if (((*it).id() == QLatin1String("ATS")) && (symbol != QString::fromUtf8("ÖS"))) {
0353             MyMoneySecurity tmp = d->m_currentCurrency;
0354             symbol = QString::fromUtf8("ÖS");
0355             d->updateCurrency((*it).id(), (*it).name(), symbol);
0356             d->m_currentCurrency = tmp;
0357         }
0358         p->setText(2, symbol);
0359 
0360         if ((*it).id() == baseCurrency) {
0361             p->setData(0, Qt::DecorationRole, Icons::get(Icon::KMyMoney));
0362             if (d->m_currentCurrency.id().isEmpty())
0363                 first = p;
0364         } else {
0365             p->setData(0, Qt::DecorationRole, empty);
0366         }
0367 
0368         // if we had a previously selected
0369         if (!d->m_currentCurrency.id().isEmpty()) {
0370             if (d->m_currentCurrency.id() == p->text(1))
0371                 first = p;
0372         } else if ((*it).id() == localCurrency && !first)
0373             first = p;
0374     }
0375     d->ui->m_removeUnusedCurrencyButton->setDisabled(list.count() <= 1);
0376 
0377     connect(d->ui->m_currencyList, &QTreeWidget::currentItemChanged, this, static_cast<void (KCurrencyEditDlg::*)(QTreeWidgetItem *, QTreeWidgetItem *)>(&KCurrencyEditDlg::slotSelectCurrency));
0378     connect(d->ui->m_currencyList, &QTreeWidget::itemChanged, this, static_cast<void (KCurrencyEditDlg::*)(QTreeWidgetItem *, int)>(&KCurrencyEditDlg::slotUpdateCurrency));
0379 
0380     if (first == 0)
0381         first = d->ui->m_currencyList->invisibleRootItem()->child(0);
0382     if (first != 0) {
0383         d->ui->m_currencyList->setCurrentItem(first);
0384         d->ui->m_currencyList->scrollToItem(first);
0385     }
0386 
0387     slotSelectCurrency(first);
0388     d->m_inLoading = false;
0389 }
0390 
0391 void KCurrencyEditDlg::slotUpdateCurrency(QTreeWidgetItem* citem, int)
0392 {
0393     slotUpdateCurrency(citem, nullptr);
0394 }
0395 
0396 void KCurrencyEditDlg::slotUpdateCurrency(QTreeWidgetItem* citem, QTreeWidgetItem *pitem)
0397 {
0398     Q_D(KCurrencyEditDlg);
0399     Q_UNUSED(pitem)
0400     // if there is no current item selected, exit
0401     if (!d->ui->m_currencyList->currentItem() || citem != d->ui->m_currencyList->currentItem())
0402         return;
0403 
0404     const auto newName = d->ui->m_currencyList->currentItem()->text(0);
0405     const auto newSymbol = d->ui->m_currencyList->currentItem()->text(2);
0406 
0407     // verify that the stored currency id is not empty and the edited fields are not empty either
0408     if (!d->m_currentCurrency.id().isEmpty()
0409             && !newSymbol.isEmpty()
0410             && !newName.isEmpty()) {
0411         d->updateCurrency(d->m_currentCurrency.id(), newName, newSymbol);
0412     }
0413 }
0414 
0415 void KCurrencyEditDlg::slotSelectCurrency(const QString& id)
0416 {
0417     Q_D(KCurrencyEditDlg);
0418     QTreeWidgetItemIterator it(d->ui->m_currencyList);
0419 
0420     while (*it) {
0421         if ((*it)->text(1) == id) {
0422             QSignalBlocker blocked(d->ui->m_currencyList);
0423             slotSelectCurrency(*it);
0424             d->ui->m_currencyList->setCurrentItem(*it);
0425             d->ui->m_currencyList->scrollToItem(*it);
0426             break;
0427         }
0428         ++it;
0429     }
0430 }
0431 
0432 void KCurrencyEditDlg::slotSelectCurrency(QTreeWidgetItem *citem, QTreeWidgetItem *pitem)
0433 {
0434     Q_UNUSED(pitem)
0435     slotSelectCurrency(citem);
0436 }
0437 
0438 void KCurrencyEditDlg::slotSelectCurrency(QTreeWidgetItem *item)
0439 {
0440     Q_D(KCurrencyEditDlg);
0441     auto file = MyMoneyFile::instance();
0442     QString baseId;
0443     try {
0444         baseId = MyMoneyFile::instance()->baseCurrency().id();
0445     } catch (const MyMoneyException &) {
0446     }
0447 
0448     if (item) {
0449         try {
0450             d->m_currentCurrency = file->security(item->text(1));
0451 
0452         } catch (const MyMoneyException &) {
0453             d->m_currentCurrency = MyMoneySecurity();
0454         }
0455 
0456         QBitArray skip((int)eStorage::Reference::Count);
0457         skip.fill(false);
0458         skip.setBit((int)eStorage::Reference::Price);
0459 
0460         const bool rc1 = d->m_currentCurrency.id() == baseId;
0461         const bool rc2 = file->isReferenced(d->m_currentCurrency, skip);
0462         const int count = d->ui->m_currencyList->selectedItems().count();
0463 
0464         d->ui->m_selectBaseCurrencyButton->setDisabled(rc1 || count != 1);
0465         d->ui->m_editCurrencyButton->setDisabled(count != 1);
0466         d->ui->m_removeCurrencyButton->setDisabled((rc1 || rc2) && count <= 1);
0467         // Q_EMIT selectObject(d->m_currentCurrency);
0468     }
0469 }
0470 
0471 void KCurrencyEditDlg::slotItemSelectionChanged()
0472 {
0473     Q_D(KCurrencyEditDlg);
0474     int count = d->ui->m_currencyList->selectedItems().count();
0475     if (!d->ui->m_selectBaseCurrencyButton->isEnabled() && count == 1)
0476         slotSelectCurrency(d->ui->m_currencyList->currentItem());
0477     if (count > 1)
0478         d->ui->m_removeCurrencyButton->setEnabled(true);
0479 }
0480 
0481 void KCurrencyEditDlg::slotShowCurrencyMenu(const QPoint& p)
0482 {
0483     Q_D(KCurrencyEditDlg);
0484     auto item = d->ui->m_currencyList->itemAt(p);
0485     if (item) {
0486         const auto sec = item->data(0, Qt::UserRole).value<MyMoneySecurity>();
0487         const auto file = MyMoneyFile::instance();
0488         QBitArray skip((int)eStorage::Reference::Count);
0489         skip.fill(false);
0490         skip.setBit((int)eStorage::Reference::Transaction);
0491         const auto cond1 = !sec.id().isEmpty();
0492         const auto cond2 = cond1 && !file->isReferenced(sec, skip);
0493         const auto cond3 = cond1 && sec.id() != file->baseCurrency().id();
0494         auto menu = new QMenu;
0495         typedef void(KCurrencyEditDlg::*KCurrencyEditDlgFunc)();
0496         struct actionInfo {
0497             eMenu::Action        action;
0498             KCurrencyEditDlgFunc callback;
0499             QString              text;
0500             Icon                 icon;
0501             bool                 enabled;
0502         };
0503 
0504         const QVector<actionInfo> actionInfos {
0505             {eMenu::Action::NewCurrency,      &KCurrencyEditDlg::slotNewCurrency,     i18n("New currency"),            Icon::DocumentNew, true},
0506             {eMenu::Action::RenameCurrency,   &KCurrencyEditDlg::slotRenameCurrency,  i18n("Rename currency"),         Icon::EditRename,  cond1},
0507             {eMenu::Action::DeleteCurrency,   &KCurrencyEditDlg::slotDeleteCurrency,  i18n("Delete currency"),         Icon::EditRemove,  cond2},
0508             {eMenu::Action::SetBaseCurrency,  &KCurrencyEditDlg::slotSetBaseCurrency, i18n("Select as base currency"), Icon::KMyMoney,    cond3},
0509         };
0510 
0511         QList<QAction*> LUTActions;
0512         for (const auto& info : actionInfos) {
0513             auto a = new QAction(Icons::get(info.icon), info.text, nullptr); // WARNING: no empty Icon::Empty here
0514             a->setEnabled(info.enabled);
0515             connect(a, &QAction::triggered, this, info.callback);
0516             LUTActions.append(a);
0517         }
0518         menu->addSection(i18nc("@title:menu", "Currency options"));
0519         menu->addActions(LUTActions);
0520         menu->exec(QCursor::pos());
0521     }
0522 }
0523 
0524 void KCurrencyEditDlg::slotSelectBaseCurrency()
0525 {
0526     Q_D(KCurrencyEditDlg);
0527     if (!d->m_currentCurrency.id().isEmpty()) {
0528         QTreeWidgetItem* const p = d->ui->m_currencyList->currentItem();
0529         d->setBaseCurrency(d->m_currentCurrency);
0530         // in case the dataChanged() signal was not sent out (nested FileTransaction)
0531         // we update the list manually
0532         if (p == d->ui->m_currencyList->currentItem())
0533             slotLoadCurrencies();
0534     }
0535 }
0536 
0537 void KCurrencyEditDlg::slotAddCurrency()
0538 {
0539     Q_D(KCurrencyEditDlg);
0540     QTreeWidgetItemIterator it(d->ui->m_currencyList); // iterate over whole tree
0541     QList<QString> currencyIdList;
0542     while (*it) {
0543         const auto currencyId = (*it)->data(0, Qt::UserRole).value<MyMoneySecurity>().id();
0544         if (!currencyId.isEmpty()) {
0545             currencyIdList.append(currencyId);
0546         }
0547         ++it;
0548     }
0549     d->m_availableCurrencyDlg = new KAvailableCurrencyDlg(currencyIdList); // create new dialog for selecting currencies to add
0550     if (d->m_availableCurrencyDlg->exec() != QDialog::Rejected) {
0551         auto file = MyMoneyFile::instance();
0552         QMap<MyMoneySecurity, MyMoneyPrice> ancientCurrencies = file->ancientCurrencies();
0553         MyMoneyFileTransaction ft;
0554         const QList<QTreeWidgetItem*> currencyRows = d->m_availableCurrencyDlg->selectedItems(); // get selected currencies from new dialog
0555         for (const auto& currencyRow : currencyRows) {
0556             MyMoneySecurity currency = currencyRow->data(0, Qt::UserRole).value<MyMoneySecurity>();
0557             file->addCurrency(currency);
0558             if (ancientCurrencies.value(currency, MyMoneyPrice()) != MyMoneyPrice()) { // if ancient currency is added...
0559                 file->addPrice(ancientCurrencies[currency]);                             // ...we want to add last known exchange rate as well
0560             } else {
0561                 // check if a new currency is added and the old one is already on file.
0562                 // in that case, we want to add the last know exchange rate as well
0563                 for (const auto &price : qAsConst(ancientCurrencies)) {
0564                     QString ancientCurrencyId;
0565                     if (price.from() == currency.id()) {
0566                         ancientCurrencyId = price.to();
0567                     } else if (price.to() == currency.id()) {
0568                         ancientCurrencyId = price.from();
0569                     }
0570                     if (!ancientCurrencyId.isEmpty()) {
0571                         // we found a replacement record, so we look for the
0572                         // older variant
0573                         try {
0574                             const auto ancientCurrency = file->currency(ancientCurrencyId);
0575                             if (!ancientCurrency.id().isEmpty()) {
0576                                 file->addPrice(ancientCurrencies[ancientCurrency]);
0577                             }
0578                         } catch (MyMoneyException&) {
0579                             // nothing to do because ancient currency is not on file
0580                         }
0581                         break;
0582                     }
0583                 }
0584             }
0585         }
0586         ft.commit();
0587         d->ui->m_removeUnusedCurrencyButton->setDisabled(file->currencyList().count() <= 1);
0588     }
0589     delete d->m_availableCurrencyDlg;
0590 }
0591 
0592 void KCurrencyEditDlg::slotRemoveCurrency()
0593 {
0594     Q_D(KCurrencyEditDlg);
0595     d->removeCurrency(KCurrencyEditDlgPrivate::RemoveSelected);
0596 }
0597 
0598 void KCurrencyEditDlg::slotRemoveUnusedCurrency()
0599 {
0600     Q_D(KCurrencyEditDlg);
0601     d->removeCurrency(KCurrencyEditDlgPrivate::RemoveUnused);
0602 }
0603 
0604 void KCurrencyEditDlg::slotEditCurrency()
0605 {
0606     Q_D(KCurrencyEditDlg);
0607     auto currency = d->ui->m_currencyList->currentItem()->data(0, Qt::UserRole).value<MyMoneySecurity>();
0608     currency.setSecurityType(eMyMoney::Security::Type::Currency);
0609     d->editCurrency(currency);
0610 
0611     // update the model data
0612     const auto item = d->ui->m_currencyList->currentItem();
0613     item->setData(0, Qt::UserRole, QVariant::fromValue(currency));
0614     item->setText(0, currency.name());
0615     item->setText(1, currency.id());
0616     item->setText(2, currency.tradingSymbol());
0617 }
0618 
0619 void KCurrencyEditDlg::slotNewCurrency()
0620 {
0621     Q_D(KCurrencyEditDlg);
0622     MyMoneySecurity currency;
0623     currency.setSecurityType(eMyMoney::Security::Type::Currency);
0624     currency.setRoundingMethod(AlkValue::RoundNever);
0625     if (d->editCurrency(currency)) {
0626         slotSelectCurrency(currency.id());
0627     }
0628 }
0629 
0630 void KCurrencyEditDlg::slotRenameCurrency()
0631 {
0632     Q_D(KCurrencyEditDlg);
0633     QTreeWidgetItemIterator it_l(d->ui->m_currencyList, QTreeWidgetItemIterator::Selected);
0634     QTreeWidgetItem* it_v;
0635     if ((it_v = *it_l) != nullptr) {
0636         d->ui->m_currencyList->editItem(it_v, 0);
0637     }
0638 }
0639 
0640 void KCurrencyEditDlg::slotDeleteCurrency()
0641 {
0642     Q_D(KCurrencyEditDlg);
0643     if (!d->m_currentCurrency.id().isEmpty()) {
0644         MyMoneyFileTransaction ft;
0645         try {
0646             MyMoneyFile::instance()->removeCurrency(d->m_currentCurrency);
0647             ft.commit();
0648         } catch (const MyMoneyException &e) {
0649             KMessageBox::error(this, i18n("Cannot delete currency %1. %2", d->m_currentCurrency.name(), QString::fromLatin1(e.what())), i18n("Delete currency"));
0650         }
0651     }
0652 }
0653 
0654 void KCurrencyEditDlg::slotSetBaseCurrency()
0655 {
0656     Q_D(KCurrencyEditDlg);
0657     if (!d->m_currentCurrency.id().isEmpty()) {
0658         if (d->m_currentCurrency.id() != MyMoneyFile::instance()->baseCurrency().id()) {
0659             MyMoneyFileTransaction ft;
0660             try {
0661                 MyMoneyFile::instance()->setBaseCurrency(d->m_currentCurrency);
0662                 ft.commit();
0663             } catch (const MyMoneyException &e) {
0664                 KMessageBox::error(this, i18n("Cannot set %1 as base currency: %2", d->m_currentCurrency.name(), QString::fromLatin1(e.what())), i18n("Set base currency"));
0665             }
0666         }
0667     }
0668 }