File indexing completed on 2024-05-12 16:44:10

0001 /*
0002     SPDX-FileCopyrightText: 2009-2011 Laurent Montel <montel@kde.org>
0003     SPDX-FileCopyrightText: 2017 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "transactionsortoption.h"
0008 
0009 // ----------------------------------------------------------------------------
0010 // QT Includes
0011 
0012 #include <QIcon>
0013 
0014 // ----------------------------------------------------------------------------
0015 // KDE Includes
0016 
0017 // ----------------------------------------------------------------------------
0018 // Project Includes
0019 
0020 #include "icons/icons.h"
0021 #include "widgetenums.h"
0022 
0023 #include "ui_transactionsortoption.h"
0024 
0025 using namespace eWidgets;
0026 using namespace Icons;
0027 
0028 static const char * sortOrderText[] = {
0029     I18N_NOOP2("Unknown sort order", "Unknown"),
0030     I18N_NOOP("Post date"),
0031     I18N_NOOP("Date entered"),
0032     I18N_NOOP("Payee"),
0033     I18N_NOOP("Amount"),
0034     I18N_NOOP("Number"),
0035     I18N_NOOP("Entry order"),
0036     I18N_NOOP("Type"),
0037     I18N_NOOP("Category"),
0038     I18N_NOOP("Reconcile state"),
0039     I18N_NOOP("Security"),
0040     // add new values above this comment line
0041 };
0042 
0043 TransactionSortOption::TransactionSortOption(QWidget *parent) :
0044     QWidget(parent),
0045     ui(new Ui::TransactionSortOption)
0046 {
0047     ui->setupUi(this);
0048 
0049     ui->m_addButton->setIcon(Icons::get(Icon::ArrowRight));
0050     ui->m_removeButton->setIcon(Icons::get(Icon::ArrowLeft));
0051     ui->m_upButton->setIcon(Icons::get(Icon::ArrowUp));
0052     ui->m_downButton->setIcon(Icons::get(Icon::ArrowDown));
0053 
0054     // don't allow sorting of the selected entries
0055     ui->m_selectedList->setSortingEnabled(false);
0056 
0057     connect(ui->m_addButton, &QPushButton::pressed, this, &TransactionSortOption::slotAddItem);
0058     connect(ui->m_removeButton, &QPushButton::pressed, this, &TransactionSortOption::slotRemoveItem);
0059     connect(ui->m_upButton, &QPushButton::pressed, this, &TransactionSortOption::slotUpItem);
0060     connect(ui->m_downButton, &QPushButton::pressed, this, &TransactionSortOption::slotDownItem);
0061 
0062     connect(ui->m_availableList, &QListWidget::currentItemChanged, this, &TransactionSortOption::slotUpdateButtons);
0063     connect(ui->m_selectedList, &QListWidget::currentItemChanged, this, &TransactionSortOption::slotUpdateButtons);
0064     connect(ui->m_selectedList, &QListWidget::doubleClicked, this, &TransactionSortOption::slotToggleDirection);
0065 
0066     setSettings(QString());
0067 }
0068 
0069 TransactionSortOption::~TransactionSortOption()
0070 {
0071     delete ui;
0072 }
0073 
0074 /**
0075   * Setup the two lists according to the elements found in @a list.
0076   * If an item is negative, it will show up in the available list,
0077   * if positive, it shows up in the selected list.
0078   *
0079   * Special care is taken about the two values @a EntryDateSort and
0080   * @a EntryOrderSort. These two entries cannot (should not) exist
0081   * alone. Inside this widget, only the @a EntryOrderSort is used.
0082   *
0083   * setSettings() takes care of hiding the @a EntryDateSort item and if
0084   * it exists in @p settings without @a EntryOrderSort being present, it
0085   * will add @a EntryOrderSort.
0086   */
0087 void TransactionSortOption::setSettings(const QString& settings)
0088 {
0089     ui->m_availableList->clear();
0090     ui->m_availableList->setCurrentItem(0);
0091     ui->m_selectedList->clear();
0092     ui->m_selectedList->setCurrentItem(0);
0093 
0094     QStringList list = settings.split(',', QString::SkipEmptyParts);
0095     QMap<int, bool> selectedMap;
0096 
0097     // fill selected list
0098     QStringList::const_iterator it_s;
0099     QListWidgetItem* last = 0;
0100     int dateSign = 1;
0101     for (it_s = list.constBegin(); it_s != list.constEnd(); ++it_s) {
0102         int val = (*it_s).toInt();
0103         selectedMap[abs(val)] = true;
0104         // skip EntryDateSort but keep sign
0105         if (abs(val) == static_cast<int>(SortField::EntryDate)) {
0106             dateSign = (val < 0) ? -1 : 1;
0107             continue;
0108         }
0109         last = addEntry(ui->m_selectedList, last, val);
0110     }
0111 
0112     // make sure to create EntryOrderSort if missing but required
0113     if (selectedMap.find(static_cast<int>(SortField::EntryDate)) != selectedMap.end()
0114             && selectedMap.find(static_cast<int>(SortField::EntryOrder)) == selectedMap.end()) {
0115         int val = dateSign * static_cast<int>(SortField::EntryOrder);
0116         selectedMap[static_cast<int>(SortField::EntryOrder)] = true;
0117         last = addEntry(ui->m_selectedList, last, val);
0118     }
0119 
0120     // fill available list
0121     for (int i = static_cast<int>(SortField::PostDate);
0122             i < static_cast<int>(SortField::MaxFields); ++i) {
0123         // Never add EntryDateSort
0124         if (i == static_cast<int>(SortField::EntryDate))
0125             continue;
0126         // Only add those, that are not present in the list of selected items
0127         if (selectedMap.find(i) == selectedMap.end()) {
0128             int val = i;
0129             if (i == static_cast<int>(SortField::Value))
0130                 val = -val;
0131             addEntry(ui->m_availableList, 0, val);
0132         }
0133     }
0134 
0135     // update the current item on the lists
0136     QListWidgetItem* p;
0137     if ((p = ui->m_availableList->item(0)) != 0) {
0138         ui->m_availableList->setCurrentItem(p);
0139     }
0140     if ((p = ui->m_selectedList->item(0)) != 0) {
0141         ui->m_selectedList->setCurrentItem(p);
0142     }
0143 
0144     slotUpdateButtons();
0145 }
0146 
0147 QListWidgetItem* TransactionSortOption::addEntry(QListWidget* p, QListWidgetItem* after, int idx)
0148 {
0149     auto txt = sortOrderToText(static_cast<SortField>(abs(idx)));
0150     if (txt.isEmpty())
0151         txt = "Unknown";    // i18n should be handled in sortOptionToText()
0152 
0153     int row = p->row(after) + 1;
0154     p->insertItem(row, txt);
0155     auto item = p->item(row);
0156     int direction = (idx >= 0) ? 1 : -1;
0157     item->setData(Qt::UserRole, QVariant(direction));
0158     setDirectionIcon(item);
0159     return item;
0160 }
0161 
0162 void TransactionSortOption::slotToggleDirection()
0163 {
0164     const auto item = ui->m_selectedList->currentItem();
0165     if (item) {
0166         int direction = item->data(Qt::UserRole).toInt() * (-1);
0167         item->setData(Qt::UserRole, QVariant(direction));
0168         setDirectionIcon(item);
0169         emit settingsChanged(settings());
0170     }
0171 }
0172 
0173 void TransactionSortOption::setDirectionIcon(QListWidgetItem* item)
0174 {
0175     if (item->data(Qt::UserRole).toInt() > 0) {
0176         item->setIcon(Icons::get(Icon::SortAscending));
0177     } else {
0178         item->setIcon(Icons::get(Icon::SortDescending));
0179     }
0180 }
0181 
0182 QString TransactionSortOption::settings() const
0183 {
0184     QString rc;
0185     auto item = dynamic_cast<QListWidgetItem*>(ui->m_selectedList->item(0));
0186     while (item) {
0187         auto option = textToSortOrder(item->text());
0188         // if we look at the EntryOrderSort option, we have to make
0189         // sure, that the EntryDateSort is prepended
0190         if (option == SortField::EntryOrder) {
0191             rc  += QString::number(static_cast<int>(SortField::EntryDate) * item->data(Qt::UserRole).toInt()) + ',';
0192         }
0193         rc += QString::number((int)textToSortOrder(item->text()) * item->data(Qt::UserRole).toInt());
0194         item = ui->m_selectedList->item(ui->m_selectedList->row(item) + 1);
0195         if (item != 0)
0196             rc += ',';
0197     }
0198     return rc;
0199 }
0200 
0201 void TransactionSortOption::slotUpdateButtons()
0202 {
0203     auto availableItem = ui->m_availableList->currentItem();
0204     auto selectedItem = ui->m_selectedList->currentItem();
0205     ui->m_addButton->setEnabled(availableItem != 0);
0206     ui->m_removeButton->setEnabled(selectedItem != 0);
0207     if (selectedItem) {
0208         ui->m_upButton->setEnabled(ui->m_selectedList->row(selectedItem) != 0);
0209         ui->m_downButton->setEnabled(ui->m_selectedList->row(selectedItem) < ui->m_selectedList->count() - 1);
0210     } else {
0211         ui->m_upButton->setEnabled(false);
0212         ui->m_downButton->setEnabled(false);
0213     }
0214 }
0215 
0216 void TransactionSortOption::slotAddItem()
0217 {
0218     QListWidgetItem* item;
0219     if ((item = ui->m_availableList->currentItem()) != 0) {
0220         auto next = ui->m_availableList->item(ui->m_availableList->row(item) + 1);
0221         if (!next)
0222             next = ui->m_availableList->item(ui->m_availableList->row(item) + 1);
0223         ui->m_availableList->takeItem(ui->m_availableList->row(item));
0224         ui->m_selectedList->addItem(item);
0225         ui->m_addButton->setEnabled((ui->m_availableList->count() > 0));
0226         if (next) {
0227             ui->m_availableList->setCurrentItem(next);
0228         }
0229         emit settingsChanged(settings());
0230     }
0231 }
0232 
0233 void TransactionSortOption::slotRemoveItem()
0234 {
0235     QListWidgetItem* item;
0236     if ((item = ui->m_selectedList->currentItem()) != 0) {
0237         auto next = ui->m_selectedList->item(ui->m_selectedList->row(item) + 1);
0238         if (!next)
0239             next = ui->m_selectedList->item(ui->m_selectedList->row(item) + 1);
0240         ui->m_selectedList->takeItem(ui->m_selectedList->row(item));
0241         ui->m_availableList->addItem(item);
0242         ui->m_removeButton->setEnabled(ui->m_selectedList->count() > 0);
0243         if (next) {
0244             ui->m_selectedList->setCurrentItem(next);
0245         }
0246         emit settingsChanged(settings());
0247     }
0248 }
0249 
0250 void TransactionSortOption::slotUpItem()
0251 {
0252     auto item = ui->m_selectedList->currentItem();
0253     auto prev = ui->m_selectedList->item(ui->m_selectedList->row(item) - 1);
0254     int prevRow = ui->m_selectedList->row(prev);
0255     if (prev) {
0256         ui->m_selectedList->takeItem(ui->m_selectedList->row(item));
0257         ui->m_selectedList->insertItem(prevRow, item);
0258         ui->m_selectedList->setCurrentRow(ui->m_selectedList->row(item));
0259         ui->m_upButton->setEnabled(ui->m_selectedList->row(item) > 0);
0260         ui->m_downButton->setEnabled(ui->m_selectedList->row(item) < ui->m_selectedList->count() - 1);
0261         emit settingsChanged(settings());
0262     }
0263 }
0264 
0265 void TransactionSortOption::slotDownItem()
0266 {
0267     auto item = ui->m_selectedList->currentItem();
0268     auto next = ui->m_selectedList->item(ui->m_selectedList->row(item) + 1);
0269     int nextRow = ui->m_selectedList->row(next);
0270     if (next) {
0271         ui->m_selectedList->takeItem(ui->m_selectedList->row(item));
0272         ui->m_selectedList->insertItem(nextRow, item);
0273         ui->m_selectedList->setCurrentRow(ui->m_selectedList->row(item));
0274         ui->m_upButton->setEnabled(ui->m_selectedList->row(item) > 0);
0275         ui->m_downButton->setEnabled(ui->m_selectedList->row(item) < ui->m_selectedList->count() - 1);
0276         emit settingsChanged(settings());
0277     }
0278 }
0279 
0280 SortField TransactionSortOption::textToSortOrder(const QString& text)
0281 {
0282     for (auto idx = 1; idx < static_cast<int>(SortField::MaxFields); ++idx) {
0283         if (text == i18n(sortOrderText[idx])) {
0284             return static_cast<SortField>(idx);
0285         }
0286     }
0287     return SortField::Unknown;
0288 }
0289 
0290 QString TransactionSortOption::sortOrderToText(SortField idx)
0291 {
0292     if ((int)idx < (int)SortField::PostDate || (int)idx >= (int)SortField::MaxFields)
0293         idx = SortField::Unknown;
0294     return i18n(sortOrderText[(int)idx]);
0295 }