diff --git a/kmymoney/plugins/csv/import/bankingwizardpage.cpp b/kmymoney/plugins/csv/import/bankingwizardpage.cpp index 26f7a6982..236cb13a1 100644 --- a/kmymoney/plugins/csv/import/bankingwizardpage.cpp +++ b/kmymoney/plugins/csv/import/bankingwizardpage.cpp @@ -1,396 +1,430 @@ /* * Copyright 2011-2017 Allan Anderson * Copyright 2016-2018 Łukasz Wojniłowicz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "bankingwizardpage.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes #include "csvwizard.h" #include "core/csvimportercore.h" #include "ui_bankingwizardpage.h" // ---------------------------------------------------------------------------- BankingPage::BankingPage(CSVWizard *dlg, CSVImporterCore *imp) : CSVWizardPage(dlg, imp), ui(new Ui::BankingPage) { ui->setupUi(this); connect(ui->m_clear, &QAbstractButton::clicked, this, &BankingPage::clearColumns); connect(ui->m_radioAmount, &QAbstractButton::toggled, this, &BankingPage::amountToggled); connect(ui->m_radioDebitCredit, &QAbstractButton::toggled, this, &BankingPage::debitCreditToggled); connect(ui->m_oppositeSigns, &QAbstractButton::clicked, this, &BankingPage::oppositeSignsClicked); // initialize column names m_dlg->m_colTypeName.insert(Column::Payee,i18n("Payee")); m_dlg->m_colTypeName.insert(Column::Number,i18n("Number")); m_dlg->m_colTypeName.insert(Column::Debit,i18n("Debit")); m_dlg->m_colTypeName.insert(Column::Credit,i18n("Credit")); m_dlg->m_colTypeName.insert(Column::Date,i18n("Date")); m_dlg->m_colTypeName.insert(Column::Amount,i18n("Amount")); m_dlg->m_colTypeName.insert(Column::Category,i18n("Category")); m_dlg->m_colTypeName.insert(Column::Memo,i18n("Memo")); m_profile = dynamic_cast(m_imp->m_profile); - connect(ui->m_amountCol, SIGNAL(currentIndexChanged(int)), this, SLOT(amountColSelected(int))); - connect(ui->m_debitCol, SIGNAL(currentIndexChanged(int)), this, SLOT(debitColSelected(int))); - connect(ui->m_creditCol, SIGNAL(currentIndexChanged(int)), this, SLOT(creditColSelected(int))); - connect(ui->m_memoCol, SIGNAL(currentIndexChanged(int)), this, SLOT(memoColSelected(int))); - connect(ui->m_numberCol, SIGNAL(currentIndexChanged(int)), this, SLOT(numberColSelected(int))); - connect(ui->m_dateCol, SIGNAL(currentIndexChanged(int)), this, SLOT(dateColSelected(int))); - connect(ui->m_payeeCol, SIGNAL(currentIndexChanged(int)), this, SLOT(payeeColSelected(int))); - connect(ui->m_categoryCol, SIGNAL(currentIndexChanged(int)), this, SLOT(categoryColSelected(int))); + void (QComboBox::* signal)(int) = &QComboBox::currentIndexChanged; + connect(ui->m_amountCol, signal, this, &BankingPage::amountColSelected); + connect(ui->m_debitCol, signal, this, &BankingPage::debitColSelected); + connect(ui->m_creditCol, signal, this, &BankingPage::creditColSelected); + connect(ui->m_memoCol, signal, this, &BankingPage::memoColSelected); + connect(ui->m_numberCol, signal, this, &BankingPage::numberColSelected); + connect(ui->m_dateCol, signal, this, &BankingPage::dateColSelected); + connect(ui->m_payeeCol, signal, this, &BankingPage::payeeColSelected); + connect(ui->m_categoryCol, signal, this, &BankingPage::categoryColSelected); + + connect(ui->m_clearMemoColumns, &QToolButton::clicked, this, &BankingPage::clearMemoColumns); + + updateCurrentMemoSelection(); } BankingPage::~BankingPage() { delete ui; } void BankingPage::initializePage() { QHash columns {{Column::Amount, ui->m_amountCol}, {Column::Debit, ui->m_debitCol}, {Column::Credit, ui->m_creditCol}, {Column::Memo, ui->m_memoCol}, {Column::Number, ui->m_numberCol}, {Column::Date, ui->m_dateCol}, {Column::Payee, ui->m_payeeCol}, {Column::Category, ui->m_categoryCol}}; if (ui->m_dateCol->count() != m_imp->m_file->m_columnCount) m_dlg->initializeComboBoxes(columns); columns.remove(Column::Memo); - for (auto it = columns.cbegin(); it != columns.cend(); ++it) + for (auto it = columns.cbegin(); it != columns.cend(); ++it) { it.value()->setCurrentIndex(m_profile->m_colTypeNum.value(it.key())); + } ui->m_oppositeSigns->setChecked(m_profile->m_oppositeSigns); if (m_profile->m_memoColList.count() > 0) { for (int i = 0; i < m_profile->m_memoColList.count(); ++i) ui->m_memoCol->setCurrentIndex(m_profile->m_memoColList.value(i)); } else ui->m_memoCol->setCurrentIndex(-1); if (this->m_profile->m_colTypeNum.value(Column::Debit) == -1) // If amount previously selected, set check radio_amount ui->m_radioAmount->setChecked(true); else // ...else set check radio_debCred to clear amount col ui->m_radioDebitCredit->setChecked(true); } int BankingPage::nextId() const { return CSVWizard::PageFormats; } bool BankingPage::isComplete() const { return ui->m_dateCol->currentIndex() > -1 && ui->m_payeeCol->currentIndex() > -1 && (ui->m_amountCol->currentIndex() > -1 || (ui->m_debitCol->currentIndex() > -1 && ui->m_creditCol->currentIndex() > -1)); } bool BankingPage::validateMemoComboBox() { - if (m_profile->m_memoColList.count() == 0) + if (m_profile->m_memoColList.isEmpty()) return true; + for (int i = 0; i < ui->m_memoCol->count(); ++i) { - QString txt = ui->m_memoCol->itemText(i); + const QString txt = ui->m_memoCol->itemText(i); if (txt.contains(QLatin1Char('*'))) // check if text containing '*' belongs to valid column types if (m_profile->m_colNumType.value(i) != Column::Payee) { ui->m_memoCol->setItemText(i, QString::number(i + 1)); m_profile->m_memoColList.removeOne(i); return false; } } return true; } void BankingPage::memoColSelected(int col) { if (m_profile->m_colNumType.value(col) == Column::Payee ) { int rc = KMessageBox::Yes; if (isVisible()) rc = KMessageBox::questionYesNo(m_dlg, i18n("
The '%1' field already has this column selected.
" "
If you wish to copy the Payee data to the memo field, click 'Yes'.
", m_dlg->m_colTypeName.value(m_profile->m_colNumType.value(col)))); if (rc == KMessageBox::Yes) { ui->m_memoCol->setItemText(col, QString::number(col + 1) + QLatin1Char('*')); if (!m_profile->m_memoColList.contains(col)) m_profile->m_memoColList.append(col); } else { ui->m_memoCol->setItemText(col, QString::number(col + 1)); m_profile->m_memoColList.removeOne(col); } //allow only separate memo field occupy combobox ui->m_memoCol->blockSignals(true); if (m_profile->m_colTypeNum.value(Column::Memo) != -1) ui->m_memoCol->setCurrentIndex(m_profile->m_colTypeNum.value(Column::Memo)); else ui->m_memoCol->setCurrentIndex(-1); ui->m_memoCol->blockSignals(false); - return; + + } else { + if (m_profile->m_colTypeNum.value(Column::Memo) != -1) // check if this memo has any column 'number' assigned... + m_profile->m_memoColList.removeOne(col); // ...if true remove it from memo list + + if(validateSelectedColumn(col, Column::Memo)) { + if (col != - 1 && !m_profile->m_memoColList.contains(col)) { + m_profile->m_memoColList.append(col); + qSort(m_profile->m_memoColList); + } + } } + updateCurrentMemoSelection(); +} - if (m_profile->m_colTypeNum.value(Column::Memo) != -1) // check if this memo has any column 'number' assigned... - m_profile->m_memoColList.removeOne(col); // ...if true remove it from memo list +void BankingPage::updateCurrentMemoSelection() +{ + const auto& list = m_profile->m_memoColList; + const bool haveSelection = !list.isEmpty(); + QString txt; + if (haveSelection) { + for (const auto& entry : list) { + txt += QString("%1, ").arg(entry+1); + } + txt = txt.left(txt.length()-2); + } + ui->m_currentMemoColums->setText(QString("%1").arg(txt, -30, QChar(' '))); - if(validateSelectedColumn(col, Column::Memo)) - if (col != - 1 && !m_profile->m_memoColList.contains(col)) - m_profile->m_memoColList.append(col); + ui->m_clearMemoColumns->setEnabled(haveSelection); } + void BankingPage::categoryColSelected(int col) { validateSelectedColumn(col, Column::Category); } void BankingPage::numberColSelected(int col) { validateSelectedColumn(col, Column::Number); } void BankingPage::payeeColSelected(int col) { if (validateSelectedColumn(col, Column::Payee)) - if (!validateMemoComboBox()) // user could have it already in memo so... + if (!validateMemoComboBox() && col != -1) // user could have it already in memo so... memoColSelected(col); // ...if true set memo field again } void BankingPage::dateColSelected(int col) { validateSelectedColumn(col, Column::Date); } void BankingPage::debitColSelected(int col) { validateSelectedColumn(col, Column::Debit); } void BankingPage::creditColSelected(int col) { validateSelectedColumn(col, Column::Credit); } void BankingPage::amountColSelected(int col) { validateSelectedColumn(col, Column::Amount); } void BankingPage::amountToggled(bool checked) { if (checked) { ui->m_amountCol->setEnabled(true); // disable credit & debit ui choices ui->labelBnk_amount->setEnabled(true); ui->labelBnk_credits->setEnabled(false); ui->labelBnk_debits->setEnabled(false); ui->m_debitCol->setEnabled(false); ui->m_debitCol->setCurrentIndex(-1); ui->m_creditCol->setEnabled(false); ui->m_creditCol->setCurrentIndex(-1); } } void BankingPage::debitCreditToggled(bool checked) { if (checked) { ui->m_debitCol->setEnabled(true); // if 'debit/credit' selected ui->labelBnk_debits->setEnabled(true); ui->m_creditCol->setEnabled(true); ui->labelBnk_credits->setEnabled(true); ui->m_amountCol->setEnabled(false); // disable 'amount' ui choices ui->m_amountCol->setCurrentIndex(-1); // as credit/debit chosen ui->labelBnk_amount->setEnabled(false); } } void BankingPage::oppositeSignsClicked(bool checked) { m_profile->m_oppositeSigns = checked; } void BankingPage::clearColumns() { ui->m_dateCol->setCurrentIndex(-1); ui->m_payeeCol->setCurrentIndex(-1); - ui->m_memoCol->setCurrentIndex(-1); ui->m_numberCol->setCurrentIndex(-1); ui->m_amountCol->setCurrentIndex(-1); ui->m_debitCol->setCurrentIndex(-1); ui->m_creditCol->setCurrentIndex(-1); ui->m_categoryCol->setCurrentIndex(-1); + clearMemoColumns(); +} + +void BankingPage::clearMemoColumns() +{ + m_profile->m_memoColList.clear(); + ui->m_memoCol->setCurrentIndex(-1); } void BankingPage::resetComboBox(const Column comboBox) { switch (comboBox) { case Column::Amount: ui->m_amountCol->setCurrentIndex(-1); break; case Column::Credit: ui->m_creditCol->setCurrentIndex(-1); break; case Column::Date: ui->m_dateCol->setCurrentIndex(-1); break; case Column::Debit: ui->m_debitCol->setCurrentIndex(-1); break; case Column::Memo: ui->m_memoCol->setCurrentIndex(-1); break; case Column::Number: ui->m_numberCol->setCurrentIndex(-1); break; case Column::Payee: ui->m_payeeCol->setCurrentIndex(-1); break; case Column::Category: ui->m_categoryCol->setCurrentIndex(-1); break; default: KMessageBox::sorry(m_dlg, i18n("
Field name not recognised.
'%1'
Please re-enter your column selections." , (int)comboBox), i18n("CSV import")); } } bool BankingPage::validateSelectedColumn(const int col, const Column type) { if (m_profile->m_colTypeNum.value(type) != -1) // check if this 'type' has any column 'number' assigned... m_profile->m_colNumType.remove(m_profile->m_colTypeNum[type]); // ...if true remove 'type' assigned to this column 'number' bool ret = true; if (col == -1) { // user only wanted to reset his column so allow him m_profile->m_colTypeNum[type] = col; // assign new column 'number' to this 'type' } else if (m_profile->m_colNumType.contains(col)) { // if this column 'number' has already 'type' assigned KMessageBox::information(m_dlg, i18n("The '%1' field already has this column selected.
Please reselect both entries as necessary.
", m_dlg->m_colTypeName.value(m_profile->m_colNumType.value(col)))); resetComboBox(m_profile->m_colNumType.value(col)); resetComboBox(type); ret = false; } else { m_profile->m_colTypeNum[type] = col; // assign new column 'number' to this 'type' m_profile->m_colNumType[col] = type; // assign new 'type' to this column 'number' } emit completeChanged(); return ret; } bool BankingPage::validateCreditDebit() { for (int row = m_profile->m_startLine; row <= m_profile->m_endLine; ++row) { // process credit/debit field if (m_profile->m_colTypeNum.value(Column::Credit) != -1 && m_profile->m_colTypeNum.value(Column::Debit) != -1) { QString credit = m_imp->m_file->m_model->item(row, m_profile->m_colTypeNum.value(Column::Credit))->text(); QString debit = m_imp->m_file->m_model->item(row, m_profile->m_colTypeNum.value(Column::Debit))->text(); m_imp->processCreditDebit(credit, debit); if (!credit.isEmpty() && !debit.isEmpty()) { int ret = KMessageBox::questionYesNoCancel(m_dlg, i18n("
The %1 field contains '%2'
" "
and the %3 field contains '%4'.
" "
Please choose which you wish to accept.
", m_dlg->m_colTypeName.value(Column::Debit), debit, m_dlg->m_colTypeName.value(Column::Credit), credit), i18n("CSV invalid field values"), KGuiItem(i18n("Accept %1", m_dlg->m_colTypeName.value(Column::Debit))), KGuiItem(i18n("Accept %1", m_dlg->m_colTypeName.value(Column::Credit))), KGuiItem(i18n("Cancel"))); switch(ret) { case KMessageBox::Cancel: return false; case KMessageBox::Yes: m_imp->m_file->m_model->item(row, m_profile->m_colTypeNum.value(Column::Credit))->setText(QString()); break; case KMessageBox::No: m_imp->m_file->m_model->item(row, m_profile->m_colTypeNum.value(Column::Debit))->setText(QString()); break; } } } } return true; } void BankingPage::makeQIF(const MyMoneyStatement& st, const QString& outFileName) { QFile oFile(outFileName); oFile.open(QIODevice::WriteOnly); QTextStream out(&oFile); QString buffer; QString strEType; switch (st.m_eType) { case eMyMoney::Statement::Type::CreditCard: strEType = QStringLiteral("CCard"); break; case eMyMoney::Statement::Type::Savings: case eMyMoney::Statement::Type::Checkings: default: strEType = QStringLiteral("Bank"); } if (!st.m_strAccountName.isEmpty()) { buffer.append(QStringLiteral("!Account\n")); buffer.append(QChar(QLatin1Char('N')) + st.m_strAccountName + QChar(QLatin1Char('\n'))); buffer.append(QChar(QLatin1Char('T')) + strEType + QChar(QLatin1Char('\n'))); buffer.append(QStringLiteral("^\n")); } buffer.append(QStringLiteral("!Type:") + strEType + QChar(QLatin1Char('\n'))); for (QList::const_iterator it = st.m_listTransactions.constBegin(); it != st.m_listTransactions.constEnd(); ++it) { buffer.append(QChar(QLatin1Char('D')) + it->m_datePosted.toString(QStringLiteral("MM/dd/yyyy")) + QChar(QLatin1Char('\n'))); QString txt; txt.setNum(it->m_amount.toDouble(), 'f', 4); buffer.append(QChar(QLatin1Char('T')) + txt + QChar(QLatin1Char('\n'))); buffer.append(QChar(QLatin1Char('P')) + it->m_strPayee + QChar(QLatin1Char('\n'))); if (!it->m_listSplits.isEmpty()) buffer.append(QChar(QLatin1Char('L')) + it->m_listSplits.first().m_strCategoryName + QChar(QLatin1Char('\n'))); if (!it->m_strNumber.isEmpty()) buffer.append(QChar(QLatin1Char('N')) + it->m_strNumber + QChar(QLatin1Char('\n'))); if (!it->m_strMemo.isEmpty()) buffer.append(QChar(QLatin1Char('M')) + it->m_strMemo + QChar(QLatin1Char('\n'))); buffer.append(QStringLiteral("^\n")); out << buffer;// output qif file buffer.clear(); } oFile.close(); } diff --git a/kmymoney/plugins/csv/import/bankingwizardpage.h b/kmymoney/plugins/csv/import/bankingwizardpage.h index 43f664349..7297e0e96 100644 --- a/kmymoney/plugins/csv/import/bankingwizardpage.h +++ b/kmymoney/plugins/csv/import/bankingwizardpage.h @@ -1,84 +1,86 @@ /* * Copyright 2011-2017 Allan Anderson * Copyright 2016-2018 Łukasz Wojniłowicz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BANKINGWIZARDPAGE_H #define BANKINGWIZARDPAGE_H // ---------------------------------------------------------------------------- // QT Includes // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes #include "csvwizardpage.h" // ---------------------------------------------------------------------------- class BankingProfile; class MyMoneyStatement; namespace Ui { class BankingPage; } class BankingPage : public CSVWizardPage { Q_OBJECT public: explicit BankingPage(CSVWizard *dlg, CSVImporterCore *imp); ~BankingPage(); bool validateCreditDebit(); /** * This method fills QIF file with bank/credit card data */ void makeQIF(const MyMoneyStatement &st, const QString &outFileName); private: void initializePage() final override; bool isComplete() const final override; int nextId() const final override; bool validateMemoComboBox(); void resetComboBox(const Column comboBox); bool validateSelectedColumn(const int col, const Column type); BankingProfile *m_profile; Ui::BankingPage *ui; -private Q_SLOTS: void memoColSelected(int col); void categoryColSelected(int col); void numberColSelected(int col); void payeeColSelected(int col); void dateColSelected(int col); void debitColSelected(int col); void creditColSelected(int col); void amountColSelected(int col); void amountToggled(bool checked); void debitCreditToggled(bool checked); void oppositeSignsClicked(bool checked); void clearColumns(); + void updateCurrentMemoSelection(); + void clearMemoColumns(); + }; #endif // BANKINGWIZARDPAGE_H diff --git a/kmymoney/plugins/csv/import/bankingwizardpage.ui b/kmymoney/plugins/csv/import/bankingwizardpage.ui index 8e01e25a3..4a781dc77 100644 --- a/kmymoney/plugins/csv/import/bankingwizardpage.ui +++ b/kmymoney/plugins/csv/import/bankingwizardpage.ui @@ -1,458 +1,480 @@ BankingPage 0 0 681 253 0 0 Banking Wizard Page - + Qt::Horizontal 40 20 0 0 Please select the appropriate columns to use, corresponding to your data. Qt::AlignCenter true - + false Debit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 16777215 16777215 Category Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Select column containing date field. 12 0 0 Select column containing category field. 12 false Credit Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Select column containing credit field. 12 Qt::Horizontal QSizePolicy::Minimum 6 0 0 0 false Select 'Debit/credit' if both columns exist, otherwise select 'Amount'. De&bit/credit false Date Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Select column containing amount field. 12 0 0 Select column containing debit field. 12 - - - - - 0 - 0 - - - - Clear selected column entries - - - Clear - - - Payee/Description Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - 0 - 0 - - - - Select column containing memo field. - - - 12 - - + + + + + + 0 + 0 + + + + Select column containing memo field. + + + 12 + + + + + + + Selection + + + + + + + Clear selected memo column entries + + + Clear + + + + 0 0 Select column containing payee or description field. 12 Memo Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - 0 - 0 - - - - Select if your amount column has signs improperly set. - - - Qt::LeftToRight - - - Opposite signs - - - 0 0 Select column containing number field. false 12 Number Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Amount Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Select 'Amount' if only one value column, otherwise select 'Debit/credit'. A&mount false 0 0 Qt::Horizontal + + + + + 0 + 0 + + + + Select if your amount column has signs improperly set. + + + Qt::LeftToRight + + + Opposite signs + + + + + + + + 0 + 0 + + + + Clear all selected column entries + + + Clear all + + + Qt::Horizontal 40 20 m_numberCol m_dateCol m_payeeCol m_categoryCol m_memoCol + m_clearMemoColumns m_radioAmount m_radioDebitCredit m_amountCol m_debitCol m_creditCol m_oppositeSigns m_clear