diff --git a/kmymoney/converter/mymoneystatementreader.cpp b/kmymoney/converter/mymoneystatementreader.cpp index d278d331f..02b26defb 100644 --- a/kmymoney/converter/mymoneystatementreader.cpp +++ b/kmymoney/converter/mymoneystatementreader.cpp @@ -1,1545 +1,1547 @@ /*************************************************************************** mymoneystatementreader.cpp ------------------- begin : Mon Aug 30 2004 copyright : (C) 2000-2004 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio Ace Jones ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "mymoneystatementreader.h" #include // ---------------------------------------------------------------------------- // QT Headers #include #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Headers #include #include #include #include #include #include // ---------------------------------------------------------------------------- // Project Headers #include "mymoneyfile.h" #include "mymoneyaccount.h" #include "mymoneyprice.h" #include "mymoneytransactionfilter.h" #include "mymoneypayee.h" #include "mymoneystatement.h" #include "kmymoneyglobalsettings.h" #include "transactioneditor.h" +#include "stdtransactioneditor.h" #include "kmymoneyedit.h" #include "kaccountselectdlg.h" #include "transactionmatcher.h" #include "kenterscheduledlg.h" #include "kmymoney.h" #include "kmymoneyaccountcombo.h" #include "accountsmodel.h" #include "models.h" #include "existingtransactionmatchfinder.h" #include "scheduledtransactionmatchfinder.h" +#include "dialogenums.h" using namespace eMyMoney; bool matchNotEmpty(const QString &l, const QString &r) { return !l.isEmpty() && QString::compare(l, r, Qt::CaseInsensitive) == 0; } class MyMoneyStatementReader::Private { public: Private() : transactionsCount(0), transactionsAdded(0), transactionsMatched(0), transactionsDuplicate(0), scannedCategories(false) {} const QString& feeId(const MyMoneyAccount& invAcc); const QString& interestId(const MyMoneyAccount& invAcc); QString interestId(const QString& name); QString expenseId(const QString& name); QString feeId(const QString& name); void assignUniqueBankID(MyMoneySplit& s, const MyMoneyStatement::Transaction& t_in); void setupPrice(MyMoneySplit &s, const MyMoneyAccount &splitAccount, const MyMoneyAccount &transactionAccount, const QDate &postDate); MyMoneyAccount lastAccount; MyMoneyAccount m_account; MyMoneyAccount m_brokerageAccount; QList transactions; QList payees; int transactionsCount; int transactionsAdded; int transactionsMatched; int transactionsDuplicate; QMap uniqIds; QMap securitiesBySymbol; QMap securitiesByName; bool m_skipCategoryMatching; private: void scanCategories(QString& id, const MyMoneyAccount& invAcc, const MyMoneyAccount& parentAccount, const QString& defaultName); /** * This method tries to figure out the category to be used for fees and interest * from previous transactions in the given @a investmentAccount and returns the * ids of those categories in @a feesId and @a interestId. The last used category * will be returned. */ void previouslyUsedCategories(const QString& investmentAccount, QString& feesId, QString& interestId); QString nameToId(const QString&name, MyMoneyAccount& parent); private: QString m_feeId; QString m_interestId; bool scannedCategories; }; const QString& MyMoneyStatementReader::Private::feeId(const MyMoneyAccount& invAcc) { scanCategories(m_feeId, invAcc, MyMoneyFile::instance()->expense(), i18n("_Fees")); return m_feeId; } const QString& MyMoneyStatementReader::Private::interestId(const MyMoneyAccount& invAcc) { scanCategories(m_interestId, invAcc, MyMoneyFile::instance()->income(), i18n("_Dividend")); return m_interestId; } QString MyMoneyStatementReader::Private::nameToId(const QString& name, MyMoneyAccount& parent) { // Adapted from KMyMoneyApp::createAccount(MyMoneyAccount& newAccount, MyMoneyAccount& parentAccount, MyMoneyAccount& brokerageAccount, MyMoneyMoney openingBal) // Needed to find/create category:sub-categories MyMoneyFile* file = MyMoneyFile::instance(); QString id = file->categoryToAccount(name, Account::Unknown); // if it does not exist, we have to create it if (id.isEmpty()) { MyMoneyAccount newAccount; MyMoneyAccount parentAccount = parent; newAccount.setName(name) ; int pos; // check for ':' in the name and use it as separator for a hierarchy while ((pos = newAccount.name().indexOf(MyMoneyFile::AccountSeperator)) != -1) { QString part = newAccount.name().left(pos); QString remainder = newAccount.name().mid(pos + 1); const MyMoneyAccount& existingAccount = file->subAccountByName(parentAccount, part); if (existingAccount.id().isEmpty()) { newAccount.setName(part); newAccount.setAccountType(parentAccount.accountType()); file->addAccount(newAccount, parentAccount); parentAccount = newAccount; } else { parentAccount = existingAccount; } newAccount.setParentAccountId(QString()); // make sure, there's no parent newAccount.clearId(); // and no id set for adding newAccount.removeAccountIds(); // and no sub-account ids newAccount.setName(remainder); }//end while newAccount.setAccountType(parentAccount.accountType()); // make sure we have a currency. If none is assigned, we assume base currency if (newAccount.currencyId().isEmpty()) newAccount.setCurrencyId(file->baseCurrency().id()); file->addAccount(newAccount, parentAccount); id = newAccount.id(); } return id; } QString MyMoneyStatementReader::Private::expenseId(const QString& name) { MyMoneyAccount parent = MyMoneyFile::instance()->expense(); return nameToId(name, parent); } QString MyMoneyStatementReader::Private::interestId(const QString& name) { MyMoneyAccount parent = MyMoneyFile::instance()->income(); return nameToId(name, parent); } QString MyMoneyStatementReader::Private::feeId(const QString& name) { MyMoneyAccount parent = MyMoneyFile::instance()->expense(); return nameToId(name, parent); } void MyMoneyStatementReader::Private::previouslyUsedCategories(const QString& investmentAccount, QString& feesId, QString& interestId) { feesId.clear(); interestId.clear(); MyMoneyFile* file = MyMoneyFile::instance(); try { MyMoneyAccount acc = file->account(investmentAccount); MyMoneyTransactionFilter filter(investmentAccount); filter.setReportAllSplits(false); // since we assume an investment account here, we need to collect the stock accounts as well filter.addAccount(acc.accountList()); QList< QPair > list; file->transactionList(list, filter); QList< QPair >::const_iterator it_t; for (it_t = list.constBegin(); it_t != list.constEnd(); ++it_t) { const MyMoneyTransaction& t = (*it_t).first; MyMoneySplit s = (*it_t).second; MyMoneyAccount acc = file->account(s.accountId()); // stock split shouldn't be fee or interest bacause it won't play nice with dissectTransaction // it was caused by processTransactionEntry adding splits in wrong order != with manual transaction entering if (acc.accountGroup() == Account::Expense || acc.accountGroup() == Account::Income) { foreach (auto sNew , t.splits()) { acc = file->account(sNew.accountId()); if (acc.accountGroup() != Account::Expense && // shouldn't be fee acc.accountGroup() != Account::Income && // shouldn't be interest (sNew.value() != sNew.shares() || // shouldn't be checking account... (sNew.value() == sNew.shares() && sNew.price() != MyMoneyMoney::ONE))) { // ...but sometimes it may look like checking account s = sNew; break; } } } MyMoneySplit assetAccountSplit; QList feeSplits; QList interestSplits; MyMoneySecurity security; MyMoneySecurity currency; eMyMoney::Split::InvestmentTransactionType transactionType; KMyMoneyUtils::dissectTransaction(t, s, assetAccountSplit, feeSplits, interestSplits, security, currency, transactionType); if (!feeSplits.isEmpty()) { feesId = feeSplits.first().accountId(); if (!interestId.isEmpty()) break; } if (!interestSplits.isEmpty()) { interestId = interestSplits.first().accountId(); if (!feesId.isEmpty()) break; } } } catch (const MyMoneyException &) { } } void MyMoneyStatementReader::Private::scanCategories(QString& id, const MyMoneyAccount& invAcc, const MyMoneyAccount& parentAccount, const QString& defaultName) { if (!scannedCategories) { previouslyUsedCategories(invAcc.id(), m_feeId, m_interestId); scannedCategories = true; } if (id.isEmpty()) { MyMoneyFile* file = MyMoneyFile::instance(); MyMoneyAccount acc = file->accountByName(defaultName); // if it does not exist, we have to create it if (acc.id().isEmpty()) { MyMoneyAccount parent = parentAccount; acc.setName(defaultName); acc.setAccountType(parent.accountType()); acc.setCurrencyId(parent.currencyId()); file->addAccount(acc, parent); } id = acc.id(); } } void MyMoneyStatementReader::Private::assignUniqueBankID(MyMoneySplit& s, const MyMoneyStatement::Transaction& t_in) { if (! t_in.m_strBankID.isEmpty()) { // make sure that id's are unique from this point on by appending a -# // postfix if needed QString base(t_in.m_strBankID); QString hash(base); int idx = 1; for (;;) { QMap::const_iterator it; it = uniqIds.constFind(hash); if (it == uniqIds.constEnd()) { uniqIds[hash] = true; break; } hash = QString("%1-%2").arg(base).arg(idx); ++idx; } s.setBankID(hash); } } void MyMoneyStatementReader::Private::setupPrice(MyMoneySplit &s, const MyMoneyAccount &splitAccount, const MyMoneyAccount &transactionAccount, const QDate &postDate) { if (transactionAccount.currencyId() != splitAccount.currencyId()) { // a currency converstion is needed assume that split has already a proper value MyMoneyFile* file = MyMoneyFile::instance(); MyMoneySecurity toCurrency = file->security(splitAccount.currencyId()); MyMoneySecurity fromCurrency = file->security(transactionAccount.currencyId()); // get the price for the transaction's date const MyMoneyPrice &price = file->price(fromCurrency.id(), toCurrency.id(), postDate); // if the price is valid calculate the shares if (price.isValid()) { const int fract = splitAccount.fraction(toCurrency); const MyMoneyMoney &shares = s.value() * price.rate(toCurrency.id()); s.setShares(shares.convert(fract)); qDebug("Setting second split shares to %s", qPrintable(s.shares().formatMoney(toCurrency.id(), 2))); } else { qDebug("No price entry was found to convert from '%s' to '%s' on '%s'", qPrintable(fromCurrency.tradingSymbol()), qPrintable(toCurrency.tradingSymbol()), qPrintable(postDate.toString(Qt::ISODate))); } } } MyMoneyStatementReader::MyMoneyStatementReader() : d(new Private), m_userAbort(false), m_autoCreatePayee(false), m_ft(0), m_progressCallback(0) { m_askPayeeCategory = KMyMoneyGlobalSettings::askForPayeeCategory(); } MyMoneyStatementReader::~MyMoneyStatementReader() { delete d; } bool MyMoneyStatementReader::anyTransactionAdded() const { return (d->transactionsAdded != 0) ? true : false; } void MyMoneyStatementReader::setAutoCreatePayee(bool create) { m_autoCreatePayee = create; } void MyMoneyStatementReader::setAskPayeeCategory(bool ask) { m_askPayeeCategory = ask; } bool MyMoneyStatementReader::import(const MyMoneyStatement& s, QStringList& messages) { // // For testing, save the statement to an XML file // (uncomment this line) // //MyMoneyStatement::writeXMLFile(s, "Imported.Xml"); // // Select the account // d->m_account = MyMoneyAccount(); d->m_brokerageAccount = MyMoneyAccount(); m_ft = new MyMoneyFileTransaction(); d->m_skipCategoryMatching = s.m_skipCategoryMatching; // if the statement source left some information about // the account, we use it to get the current data of it if (!s.m_accountId.isEmpty()) { try { d->m_account = MyMoneyFile::instance()->account(s.m_accountId); } catch (const MyMoneyException &) { qDebug("Received reference '%s' to unknown account in statement", qPrintable(s.m_accountId)); } } if (d->m_account.id().isEmpty()) { d->m_account.setName(s.m_strAccountName); d->m_account.setNumber(s.m_strAccountNumber); switch (s.m_eType) { case MyMoneyStatement::etCheckings: d->m_account.setAccountType(Account::Checkings); break; case MyMoneyStatement::etSavings: d->m_account.setAccountType(Account::Savings); break; case MyMoneyStatement::etInvestment: //testing support for investment statements! //m_userAbort = true; //KMessageBox::error(kmymoney, i18n("This is an investment statement. These are not supported currently."), i18n("Critical Error")); d->m_account.setAccountType(Account::Investment); break; case MyMoneyStatement::etCreditCard: d->m_account.setAccountType(Account::CreditCard); break; default: d->m_account.setAccountType(Account::Unknown); break; } // we ask the user only if we have some transactions to process if (!m_userAbort && s.m_listTransactions.count() > 0) m_userAbort = ! selectOrCreateAccount(Select, d->m_account); } // see if we need to update some values stored with the account if (d->m_account.value("lastStatementBalance") != s.m_closingBalance.toString() || d->m_account.value("lastImportedTransactionDate") != s.m_dateEnd.toString(Qt::ISODate)) { if (s.m_closingBalance != MyMoneyMoney::autoCalc) { d->m_account.setValue("lastStatementBalance", s.m_closingBalance.toString()); if (s.m_dateEnd.isValid()) { d->m_account.setValue("lastImportedTransactionDate", s.m_dateEnd.toString(Qt::ISODate)); } } try { MyMoneyFile::instance()->modifyAccount(d->m_account); } catch (const MyMoneyException &) { qDebug("Updating account in MyMoneyStatementReader::startImport failed"); } } if (!d->m_account.name().isEmpty()) messages += i18n("Importing statement for account %1", d->m_account.name()); else if (s.m_listTransactions.count() == 0) messages += i18n("Importing statement without transactions"); qDebug("Importing statement for '%s'", qPrintable(d->m_account.name())); // // Process the securities // signalProgress(0, s.m_listSecurities.count(), "Importing Statement ..."); int progress = 0; QList::const_iterator it_s = s.m_listSecurities.begin(); while (it_s != s.m_listSecurities.end()) { processSecurityEntry(*it_s); signalProgress(++progress, 0); ++it_s; } signalProgress(-1, -1); // // Process the transactions // if (!m_userAbort) { try { qDebug("Processing transactions (%s)", qPrintable(d->m_account.name())); signalProgress(0, s.m_listTransactions.count(), "Importing Statement ..."); int progress = 0; QList::const_iterator it_t = s.m_listTransactions.begin(); while (it_t != s.m_listTransactions.end() && !m_userAbort) { processTransactionEntry(*it_t); signalProgress(++progress, 0); ++it_t; } qDebug("Processing transactions done (%s)", qPrintable(d->m_account.name())); } catch (const MyMoneyException &e) { if (e.what() == "USERABORT") m_userAbort = true; else qDebug("Caught exception from processTransactionEntry() not caused by USERABORT: %s", qPrintable(e.what())); } signalProgress(-1, -1); } // // process price entries // if (!m_userAbort) { try { signalProgress(0, s.m_listPrices.count(), "Importing Statement ..."); QList slist = MyMoneyFile::instance()->securityList(); QList::const_iterator it_s; for (it_s = slist.constBegin(); it_s != slist.constEnd(); ++it_s) { d->securitiesBySymbol[(*it_s).tradingSymbol()] = *it_s; d->securitiesByName[(*it_s).name()] = *it_s; } int progress = 0; QList::const_iterator it_p = s.m_listPrices.begin(); while (it_p != s.m_listPrices.end()) { processPriceEntry(*it_p); signalProgress(++progress, 0); ++it_p; } } catch (const MyMoneyException &e) { if (e.what() == "USERABORT") m_userAbort = true; else qDebug("Caught exception from processPriceEntry() not caused by USERABORT: %s", qPrintable(e.what())); } signalProgress(-1, -1); } bool rc = false; // delete all payees created in vain int payeeCount = d->payees.count(); QList::const_iterator it_p; for (it_p = d->payees.constBegin(); it_p != d->payees.constEnd(); ++it_p) { try { MyMoneyFile::instance()->removePayee(*it_p); --payeeCount; } catch (const MyMoneyException &) { // if we can't delete it, it must be in use which is ok for us } } if (s.m_closingBalance.isAutoCalc()) { messages += i18n(" Statement balance is not contained in statement."); } else { messages += i18n(" Statement balance on %1 is reported to be %2", s.m_dateEnd.toString(Qt::ISODate), s.m_closingBalance.formatMoney("", 2)); } messages += i18n(" Transactions"); messages += i18np(" %1 processed", " %1 processed", d->transactionsCount); messages += i18ncp("x transactions have been added", " %1 added", " %1 added", d->transactionsAdded); messages += i18np(" %1 matched", " %1 matched", d->transactionsMatched); messages += i18np(" %1 duplicate", " %1 duplicates", d->transactionsDuplicate); messages += i18n(" Payees"); messages += i18ncp("x transactions have been created", " %1 created", " %1 created", payeeCount); messages += QString(); // remove the Don't ask again entries KSharedConfigPtr config = KSharedConfig::openConfig(); KConfigGroup grp = config->group(QString::fromLatin1("Notification Messages")); QStringList::ConstIterator it; for (it = m_dontAskAgain.constBegin(); it != m_dontAskAgain.constEnd(); ++it) { grp.deleteEntry(*it); } config->sync(); m_dontAskAgain.clear(); rc = !m_userAbort; // finish the transaction if (rc) m_ft->commit(); delete m_ft; m_ft = 0; qDebug("Importing statement for '%s' done", qPrintable(d->m_account.name())); return rc; } void MyMoneyStatementReader::processPriceEntry(const MyMoneyStatement::Price& p_in) { MyMoneyFile* file = MyMoneyFile::instance(); QString currency = file->baseCurrency().id(); QString security; if (!p_in.m_strCurrency.isEmpty()) { security = p_in.m_strSecurity; currency = p_in.m_strCurrency; } else if (d->securitiesBySymbol.contains(p_in.m_strSecurity)) { security = d->securitiesBySymbol[p_in.m_strSecurity].id(); currency = file->security(file->security(security).tradingCurrency()).id(); } else if (d->securitiesByName.contains(p_in.m_strSecurity)) { security = d->securitiesByName[p_in.m_strSecurity].id(); currency = file->security(file->security(security).tradingCurrency()).id(); } else return; MyMoneyPrice price(security, currency, p_in.m_date, p_in.m_amount, p_in.m_sourceName.isEmpty() ? i18n("Prices Importer") : p_in.m_sourceName); MyMoneyFile::instance()->addPrice(price); } void MyMoneyStatementReader::processSecurityEntry(const MyMoneyStatement::Security& sec_in) { // For a security entry, we will just make sure the security exists in the // file. It will not get added to the investment account until it's called // for in a transaction. MyMoneyFile* file = MyMoneyFile::instance(); // check if we already have the security // In a statement, we do not know what type of security this is, so we will // not use type as a matching factor. MyMoneySecurity security; QList list = file->securityList(); QList::ConstIterator it = list.constBegin(); while (it != list.constEnd() && security.id().isEmpty()) { if (matchNotEmpty(sec_in.m_strSymbol, (*it).tradingSymbol()) || matchNotEmpty(sec_in.m_strName, (*it).name())) { security = *it; } ++it; } // if the security was not found, we have to create it while not forgetting // to setup the type if (security.id().isEmpty()) { security.setName(sec_in.m_strName); security.setTradingSymbol(sec_in.m_strSymbol); security.setTradingCurrency(file->baseCurrency().id()); security.setValue("kmm-security-id", sec_in.m_strId); security.setValue("kmm-online-source", "Yahoo"); security.setSecurityType(Security::Stock); MyMoneyFileTransaction ft; try { file->addSecurity(security); ft.commit(); qDebug() << "Created " << security.name() << " with id " << security.id(); } catch (const MyMoneyException &e) { KMessageBox::error(0, i18n("Error creating security record: %1", e.what()), i18n("Error")); } } else { qDebug() << "Found " << security.name() << " with id " << security.id(); } } void MyMoneyStatementReader::processTransactionEntry(const MyMoneyStatement::Transaction& statementTransactionUnderImport) { MyMoneyFile* file = MyMoneyFile::instance(); MyMoneyTransaction transactionUnderImport; QString dbgMsg; dbgMsg = QString("Process on: '%1', id: '%3', amount: '%2', fees: '%4'") .arg(statementTransactionUnderImport.m_datePosted.toString(Qt::ISODate)) .arg(statementTransactionUnderImport.m_amount.formatMoney("", 2)) .arg(statementTransactionUnderImport.m_strBankID) .arg(statementTransactionUnderImport.m_fees.formatMoney("", 2)); qDebug("%s", qPrintable(dbgMsg)); // mark it imported for the view transactionUnderImport.setImported(); // TODO (Ace) We can get the commodity from the statement!! // Although then we would need UI to verify transactionUnderImport.setCommodity(d->m_account.currencyId()); transactionUnderImport.setPostDate(statementTransactionUnderImport.m_datePosted); transactionUnderImport.setMemo(statementTransactionUnderImport.m_strMemo); MyMoneySplit s1; MyMoneySplit s2; MyMoneySplit sFees; MyMoneySplit sBrokerage; s1.setMemo(statementTransactionUnderImport.m_strMemo); s1.setValue(statementTransactionUnderImport.m_amount + statementTransactionUnderImport.m_fees); s1.setShares(s1.value()); s1.setNumber(statementTransactionUnderImport.m_strNumber); // set these values if a transfer split is needed at the very end. MyMoneyMoney transfervalue; // If the user has chosen to import into an investment account, determine the correct account to use MyMoneyAccount thisaccount = d->m_account; QString brokerageactid; if (thisaccount.accountType() == Account::Investment) { // determine the brokerage account brokerageactid = d->m_account.value("kmm-brokerage-account").toUtf8(); if (brokerageactid.isEmpty()) { brokerageactid = file->accountByName(statementTransactionUnderImport.m_strBrokerageAccount).id(); } if (brokerageactid.isEmpty()) { brokerageactid = file->nameToAccount(statementTransactionUnderImport.m_strBrokerageAccount); } if (brokerageactid.isEmpty()) { brokerageactid = file->nameToAccount(thisaccount.brokerageName()); } if (brokerageactid.isEmpty()) { brokerageactid = SelectBrokerageAccount(); } // find the security transacted, UNLESS this transaction didn't // involve any security. if ((statementTransactionUnderImport.m_eAction != MyMoneyStatement::Transaction::eaNone) // eaInterest transactions MAY have a security. // && (t_in.m_eAction != MyMoneyStatement::Transaction::eaInterest) && (statementTransactionUnderImport.m_eAction != MyMoneyStatement::Transaction::eaFees)) { // the correct account is the stock account which matches two criteria: // (1) it is a sub-account of the selected investment account, and // (2a) the symbol of the underlying security matches the security of the // transaction, or // (2b) the name of the security matches the name of the security of the transaction. // search through each subordinate account bool found = false; QStringList accounts = thisaccount.accountList(); QStringList::const_iterator it_account = accounts.constBegin(); QString currencyid; while (!found && it_account != accounts.constEnd()) { currencyid = file->account(*it_account).currencyId(); MyMoneySecurity security = file->security(currencyid); if (matchNotEmpty(statementTransactionUnderImport.m_strSymbol, security.tradingSymbol()) || matchNotEmpty(statementTransactionUnderImport.m_strSecurity, security.name())) { thisaccount = file->account(*it_account); found = true; } ++it_account; } // If there was no stock account under the m_acccount investment account, // add one using the security. if (!found) { // The security should always be available, because the statement file // should separately list all the securities referred to in the file, // and when we found a security, we added it to the file. if (statementTransactionUnderImport.m_strSecurity.isEmpty()) { KMessageBox::information(0, i18n("This imported statement contains investment transactions with no security. These transactions will be ignored."), i18n("Security not found"), QString("BlankSecurity")); return; } else { MyMoneySecurity security; QList list = MyMoneyFile::instance()->securityList(); QList::ConstIterator it = list.constBegin(); while (it != list.constEnd() && security.id().isEmpty()) { if (matchNotEmpty(statementTransactionUnderImport.m_strSymbol, (*it).tradingSymbol()) || matchNotEmpty(statementTransactionUnderImport.m_strSecurity, (*it).name())) { security = *it; } ++it; } if (!security.id().isEmpty()) { thisaccount = MyMoneyAccount(); thisaccount.setName(security.name()); thisaccount.setAccountType(Account::Stock); thisaccount.setCurrencyId(security.id()); currencyid = thisaccount.currencyId(); file->addAccount(thisaccount, d->m_account); qDebug() << Q_FUNC_INFO << ": created account " << thisaccount.id() << " for security " << statementTransactionUnderImport.m_strSecurity << " under account " << d->m_account.id(); } // this security does not exist in the file. else { // This should be rare. A statement should have a security entry for any // of the securities referred to in the transactions. The only way to get // here is if that's NOT the case. int ret = KMessageBox::warningContinueCancel(0, i18n("
This investment account does not contain the \"%1\" security.
" "
Transactions involving this security will be ignored.
", statementTransactionUnderImport.m_strSecurity), i18n("Security not found"), KStandardGuiItem::cont(), KStandardGuiItem::cancel()); if (ret == KMessageBox::Cancel) { m_userAbort = true; } return; } } } // Don't update price if there is no price information contained in the transaction if (statementTransactionUnderImport.m_eAction != MyMoneyStatement::Transaction::eaCashDividend && statementTransactionUnderImport.m_eAction != MyMoneyStatement::Transaction::eaShrsin && statementTransactionUnderImport.m_eAction != MyMoneyStatement::Transaction::eaShrsout) { // update the price, while we're here. in the future, this should be // an option QString basecurrencyid = file->baseCurrency().id(); const MyMoneyPrice &price = file->price(currencyid, basecurrencyid, statementTransactionUnderImport.m_datePosted, true); if (!price.isValid() && ((!statementTransactionUnderImport.m_amount.isZero() && !statementTransactionUnderImport.m_shares.isZero()) || !statementTransactionUnderImport.m_price.isZero())) { MyMoneyPrice newprice; if (!statementTransactionUnderImport.m_price.isZero()) { newprice = MyMoneyPrice(currencyid, basecurrencyid, statementTransactionUnderImport.m_datePosted, statementTransactionUnderImport.m_price.abs(), i18n("Statement Importer")); } else { newprice = MyMoneyPrice(currencyid, basecurrencyid, statementTransactionUnderImport.m_datePosted, (statementTransactionUnderImport.m_amount / statementTransactionUnderImport.m_shares).abs(), i18n("Statement Importer")); } file->addPrice(newprice); } } } s1.setAccountId(thisaccount.id()); d->assignUniqueBankID(s1, statementTransactionUnderImport); if (statementTransactionUnderImport.m_eAction == MyMoneyStatement::Transaction::eaReinvestDividend) { s1.setAction(MyMoneySplit::ActionReinvestDividend); s1.setShares(statementTransactionUnderImport.m_shares); if (!statementTransactionUnderImport.m_price.isZero()) { s1.setPrice(statementTransactionUnderImport.m_price); } else { if (statementTransactionUnderImport.m_shares.isZero()) { KMessageBox::information(0, i18n("This imported statement contains investment transactions with no share amount. These transactions will be ignored."), i18n("No share amount provided"), QString("BlankAmount")); return; } MyMoneyMoney total = -statementTransactionUnderImport.m_amount - statementTransactionUnderImport.m_fees; s1.setPrice((total / statementTransactionUnderImport.m_shares).convertPrecision(file->security(thisaccount.currencyId()).pricePrecision())); } s2.setMemo(statementTransactionUnderImport.m_strMemo); if (statementTransactionUnderImport.m_strInterestCategory.isEmpty()) s2.setAccountId(d->interestId(thisaccount)); else s2.setAccountId(d->interestId(statementTransactionUnderImport.m_strInterestCategory)); s2.setShares(-statementTransactionUnderImport.m_amount - statementTransactionUnderImport.m_fees); s2.setValue(s2.shares()); } else if (statementTransactionUnderImport.m_eAction == MyMoneyStatement::Transaction::eaCashDividend) { // Cash dividends require setting 2 splits to get all of the information // in. Split #1 will be the income split, and we'll set it to the first // income account. This is a hack, but it's needed in order to get the // amount into the transaction. if (statementTransactionUnderImport.m_strInterestCategory.isEmpty()) s1.setAccountId(d->interestId(thisaccount)); else {// Ensure category sub-accounts are dealt with properly s1.setAccountId(d->interestId(statementTransactionUnderImport.m_strInterestCategory)); } s1.setShares(-statementTransactionUnderImport.m_amount - statementTransactionUnderImport.m_fees); s1.setValue(-statementTransactionUnderImport.m_amount - statementTransactionUnderImport.m_fees); // Split 2 will be the zero-amount investment split that serves to // mark this transaction as a cash dividend and note which stock account // it belongs to. s2.setMemo(statementTransactionUnderImport.m_strMemo); s2.setAction(MyMoneySplit::ActionDividend); s2.setAccountId(thisaccount.id()); /* at this point any fees have been taken into account already * so don't deduct them again. * BUG 322381 */ transfervalue = statementTransactionUnderImport.m_amount; } else if (statementTransactionUnderImport.m_eAction == MyMoneyStatement::Transaction::eaInterest) { if (statementTransactionUnderImport.m_strInterestCategory.isEmpty()) s1.setAccountId(d->interestId(thisaccount)); else {// Ensure category sub-accounts are dealt with properly if (statementTransactionUnderImport.m_amount.isPositive()) s1.setAccountId(d->interestId(statementTransactionUnderImport.m_strInterestCategory)); else s1.setAccountId(d->expenseId(statementTransactionUnderImport.m_strInterestCategory)); } s1.setShares(-statementTransactionUnderImport.m_amount - statementTransactionUnderImport.m_fees); s1.setValue(-statementTransactionUnderImport.m_amount - statementTransactionUnderImport.m_fees); /// *********** Add split as per Div ********** // Split 2 will be the zero-amount investment split that serves to // mark this transaction as a cash dividend and note which stock account // it belongs to. s2.setMemo(statementTransactionUnderImport.m_strMemo); s2.setAction(MyMoneySplit::ActionInterestIncome); s2.setAccountId(thisaccount.id()); transfervalue = statementTransactionUnderImport.m_amount; } else if (statementTransactionUnderImport.m_eAction == MyMoneyStatement::Transaction::eaFees) { if (statementTransactionUnderImport.m_strInterestCategory.isEmpty()) s1.setAccountId(d->feeId(thisaccount)); else// Ensure category sub-accounts are dealt with properly s1.setAccountId(d->feeId(statementTransactionUnderImport.m_strInterestCategory)); s1.setShares(statementTransactionUnderImport.m_amount); s1.setValue(statementTransactionUnderImport.m_amount); transfervalue = statementTransactionUnderImport.m_amount; } else if ((statementTransactionUnderImport.m_eAction == MyMoneyStatement::Transaction::eaBuy) || (statementTransactionUnderImport.m_eAction == MyMoneyStatement::Transaction::eaSell)) { s1.setAction(MyMoneySplit::ActionBuyShares); if (!statementTransactionUnderImport.m_price.isZero()) { s1.setPrice(statementTransactionUnderImport.m_price.abs()); } else if (!statementTransactionUnderImport.m_shares.isZero()) { MyMoneyMoney total = statementTransactionUnderImport.m_amount + statementTransactionUnderImport.m_fees.abs(); s1.setPrice((total / statementTransactionUnderImport.m_shares).abs().convertPrecision(file->security(thisaccount.currencyId()).pricePrecision())); } if (statementTransactionUnderImport.m_eAction == MyMoneyStatement::Transaction::eaBuy) s1.setShares(statementTransactionUnderImport.m_shares.abs()); else s1.setShares(-statementTransactionUnderImport.m_shares.abs()); s1.setValue(-(statementTransactionUnderImport.m_amount + statementTransactionUnderImport.m_fees.abs())); transfervalue = statementTransactionUnderImport.m_amount; } else if ((statementTransactionUnderImport.m_eAction == MyMoneyStatement::Transaction::eaShrsin) || (statementTransactionUnderImport.m_eAction == MyMoneyStatement::Transaction::eaShrsout)) { s1.setValue(MyMoneyMoney()); s1.setShares(statementTransactionUnderImport.m_shares); s1.setAction(MyMoneySplit::ActionAddShares); } else if (statementTransactionUnderImport.m_eAction == MyMoneyStatement::Transaction::eaNone) { // User is attempting to import a non-investment transaction into this // investment account. This is not supportable the way KMyMoney is // written. However, if a user has an associated brokerage account, // we can stuff the transaction there. QString brokerageactid = d->m_account.value("kmm-brokerage-account").toUtf8(); if (brokerageactid.isEmpty()) { brokerageactid = file->accountByName(d->m_account.brokerageName()).id(); } if (! brokerageactid.isEmpty()) { s1.setAccountId(brokerageactid); d->assignUniqueBankID(s1, statementTransactionUnderImport); // Needed to satisfy the bankid check below. thisaccount = file->account(brokerageactid); } else { // Warning!! Your transaction is being thrown away. } } if (!statementTransactionUnderImport.m_fees.isZero()) { sFees.setMemo(i18n("(Fees) %1", statementTransactionUnderImport.m_strMemo)); sFees.setValue(statementTransactionUnderImport.m_fees); sFees.setShares(statementTransactionUnderImport.m_fees); sFees.setAccountId(d->feeId(thisaccount)); } } else { // For non-investment accounts, just use the selected account // Note that it is perfectly reasonable to import an investment statement into a non-investment account // if you really want. The investment-specific information, such as number of shares and action will // be discarded in that case. s1.setAccountId(d->m_account.id()); d->assignUniqueBankID(s1, statementTransactionUnderImport); } QString payeename = statementTransactionUnderImport.m_strPayee; if (!payeename.isEmpty()) { qDebug() << QLatin1String("Start matching payee") << payeename; QString payeeid; try { QList pList = file->payeeList(); QList::const_iterator it_p; QMap matchMap; for (it_p = pList.constBegin(); it_p != pList.constEnd(); ++it_p) { bool ignoreCase; QStringList keys; QStringList::const_iterator it_s; const MyMoneyPayee::payeeMatchType matchType = (*it_p).matchData(ignoreCase, keys); switch (matchType) { case MyMoneyPayee::matchDisabled: break; case MyMoneyPayee::matchName: case MyMoneyPayee::matchNameExact: keys << QString("%1").arg(QRegExp::escape((*it_p).name())); if(matchType == MyMoneyPayee::matchNameExact) { keys.clear(); keys << QString("^%1$").arg(QRegExp::escape((*it_p).name())); } // intentional fall through case MyMoneyPayee::matchKey: for (it_s = keys.constBegin(); it_s != keys.constEnd(); ++it_s) { QRegExp exp(*it_s, ignoreCase ? Qt::CaseInsensitive : Qt::CaseSensitive); if (exp.indexIn(payeename) != -1) { qDebug("Found match with '%s' on '%s'", qPrintable(payeename), qPrintable((*it_p).name())); matchMap[exp.matchedLength()] = (*it_p).id(); } } break; } } // at this point we can have several scenarios: // a) multiple matches // b) a single match // c) no match at all // // for c) we just do nothing, for b) we take the one we found // in case of a) we take the one with the largest matchedLength() // which happens to be the last one in the map if (matchMap.count() > 1) { qDebug("Multiple matches"); QMap::const_iterator it_m = matchMap.constEnd(); --it_m; payeeid = *it_m; } else if (matchMap.count() == 1) { qDebug("Single matches"); payeeid = *(matchMap.constBegin()); } // if we did not find a matching payee, we throw an exception and try to create it if (payeeid.isEmpty()) throw MYMONEYEXCEPTION("payee not matched"); s1.setPayeeId(payeeid); } catch (const MyMoneyException &) { MyMoneyPayee payee; int rc = KMessageBox::Yes; if (m_autoCreatePayee == false) { // Ask the user if that is what he intended to do? QString msg = i18n("Do you want to add \"%1\" as payee/receiver?\n\n", payeename); msg += i18n("Selecting \"Yes\" will create the payee, \"No\" will skip " "creation of a payee record and remove the payee information " "from this transaction. Selecting \"Cancel\" aborts the import " "operation.\n\nIf you select \"No\" here and mark the \"Do not ask " "again\" checkbox, the payee information for all following transactions " "referencing \"%1\" will be removed.", payeename); QString askKey = QString("Statement-Import-Payee-") + payeename; if (!m_dontAskAgain.contains(askKey)) { m_dontAskAgain += askKey; } rc = KMessageBox::questionYesNoCancel(0, msg, i18n("New payee/receiver"), KStandardGuiItem::yes(), KStandardGuiItem::no(), KStandardGuiItem::cancel(), askKey); } if (rc == KMessageBox::Yes) { // for now, we just add the payee to the pool and turn // on simple name matching, so that future transactions // with the same name don't get here again. // // In the future, we could open a dialog and ask for // all the other attributes of the payee, but since this // is called in the context of an automatic procedure it // might distract the user. payee.setName(payeename); payee.setMatchData(MyMoneyPayee::matchKey, true, QStringList() << QString("^%1$").arg(QRegExp::escape(payeename))); if (m_askPayeeCategory) { // We use a QPointer because the dialog may get deleted // during exec() if the parent of the dialog gets deleted. // In that case the guarded ptr will reset to 0. QPointer dialog = new QDialog(kmymoney); dialog->setWindowTitle(i18n("Default Category for Payee")); dialog->setModal(true); QWidget *mainWidget = new QWidget; QVBoxLayout *topcontents = new QVBoxLayout(mainWidget); //add in caption? and account combo here QLabel *label1 = new QLabel(i18n("Please select a default category for payee '%1'", payeename)); topcontents->addWidget(label1); auto filterProxyModel = new AccountNamesFilterProxyModel(this); filterProxyModel->setHideEquityAccounts(!KMyMoneyGlobalSettings::expertMode()); filterProxyModel->addAccountGroup(QVector {Account::Asset, Account::Liability, Account::Equity, Account::Income, Account::Expense}); auto const model = Models::instance()->accountsModel(); filterProxyModel->setSourceModel(model); filterProxyModel->setSourceColumns(model->getColumns()); filterProxyModel->sort((int)eAccountsModel::Column::Account); QPointer accountCombo = new KMyMoneyAccountCombo(filterProxyModel); topcontents->addWidget(accountCombo); mainWidget->setLayout(topcontents); QVBoxLayout *mainLayout = new QVBoxLayout; QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel|QDialogButtonBox::No|QDialogButtonBox::Yes); dialog->setLayout(mainLayout); mainLayout->addWidget(mainWidget); dialog->connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); dialog->connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); mainLayout->addWidget(buttonBox); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Yes), KGuiItem(i18n("Save Category"))); KGuiItem::assign(buttonBox->button(QDialogButtonBox::No), KGuiItem(i18n("No Category"))); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KGuiItem(i18n("Abort"))); int result = dialog->exec(); QString accountId; if (accountCombo && !accountCombo->getSelected().isEmpty()) { accountId = accountCombo->getSelected(); } delete dialog; //if they hit yes instead of no, then grab setting of account combo if (result == QDialog::Accepted) { payee.setDefaultAccountId(accountId); } else if (result != QDialog::Rejected) { //add cancel button? and throw exception like below throw MYMONEYEXCEPTION("USERABORT"); } } try { file->addPayee(payee); qDebug("Payee '%s' created", qPrintable(payee.name())); d->payees << payee; payeeid = payee.id(); s1.setPayeeId(payeeid); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Unable to add payee/receiver"), i18n("%1 thrown in %2:%3", e.what(), e.file(), e.line())); } } else if (rc == KMessageBox::No) { s1.setPayeeId(QString()); } else { throw MYMONEYEXCEPTION("USERABORT"); } } if (thisaccount.accountType() != Account::Stock) { // // Fill in other side of the transaction (category/etc) based on payee // // Note, this logic is lifted from KLedgerView::slotPayeeChanged(), // however this case is more complicated, because we have an amount and // a memo. We just don't have the other side of the transaction. // // We'll search for the most recent transaction in this account with // this payee. If this reference transaction is a simple 2-split // transaction, it's simple. If it's a complex split, and the amounts // are different, we have a problem. Somehow we have to balance the // transaction. For now, we'll leave it unbalanced, and let the user // handle it. // const MyMoneyPayee& payeeObj = MyMoneyFile::instance()->payee(payeeid); if (statementTransactionUnderImport.m_listSplits.isEmpty() && payeeObj.defaultAccountEnabled()) { MyMoneyAccount splitAccount = file->account(payeeObj.defaultAccountId()); MyMoneySplit s; s.setReconcileFlag(eMyMoney::Split::State::Cleared); s.clearId(); s.setBankID(QString()); s.setShares(-s1.shares()); s.setValue(-s1.value()); s.setAccountId(payeeObj.defaultAccountId()); s.setMemo(transactionUnderImport.memo()); s.setPayeeId(payeeid); d->setupPrice(s, splitAccount, d->m_account, statementTransactionUnderImport.m_datePosted); transactionUnderImport.addSplit(s); file->addVATSplit(transactionUnderImport, d->m_account, splitAccount, statementTransactionUnderImport.m_amount); } else if (statementTransactionUnderImport.m_listSplits.isEmpty() && !d->m_skipCategoryMatching) { MyMoneyTransactionFilter filter(thisaccount.id()); filter.addPayee(payeeid); QList list = file->transactionList(filter); if (!list.empty()) { // Default to using the most recent transaction as the reference MyMoneyTransaction t_old = list.last(); // if there is more than one matching transaction, try to be a little // smart about which one we take. for now, we'll see if there's one // with the same VALUE as our imported transaction, and if so take that one. if (list.count() > 1) { QList::ConstIterator it_trans = list.constEnd(); if (it_trans != list.constBegin()) --it_trans; while (it_trans != list.constBegin()) { MyMoneySplit s = (*it_trans).splitByAccount(thisaccount.id()); if (s.value() == s1.value()) { // keep searching if this transaction references a closed account if (!MyMoneyFile::instance()->referencesClosedAccount(*it_trans)) { t_old = *it_trans; break; } } --it_trans; } // check constBegin, just in case if (it_trans == list.constBegin()) { MyMoneySplit s = (*it_trans).splitByAccount(thisaccount.id()); if (s.value() == s1.value()) { t_old = *it_trans; } } } // Only copy the splits if the transaction found does not reference a closed account if (!MyMoneyFile::instance()->referencesClosedAccount(t_old)) { QList::ConstIterator it_split; for (it_split = t_old.splits().constBegin(); it_split != t_old.splits().constEnd(); ++it_split) { // We don't need the split that covers this account, // we just need the other ones. if ((*it_split).accountId() != thisaccount.id()) { MyMoneySplit s(*it_split); s.setReconcileFlag(eMyMoney::Split::State::NotReconciled); s.clearId(); s.setBankID(QString()); s.removeMatch(); if (t_old.splits().count() == 2) { s.setShares(-s1.shares()); s.setValue(-s1.value()); s.setMemo(s1.memo()); } MyMoneyAccount splitAccount = file->account(s.accountId()); qDebug("Adding second split to %s(%s)", qPrintable(splitAccount.name()), qPrintable(s.accountId())); d->setupPrice(s, splitAccount, d->m_account, statementTransactionUnderImport.m_datePosted); transactionUnderImport.addSplit(s); } } } } } } } s1.setReconcileFlag(statementTransactionUnderImport.m_reconcile); // Add the 'account' split if it's needed if (! transfervalue.isZero()) { // in case the transaction has a reference to the brokerage account, we use it // but if brokerageactid has already been set, keep that. if (!statementTransactionUnderImport.m_strBrokerageAccount.isEmpty() && brokerageactid.isEmpty()) { brokerageactid = file->nameToAccount(statementTransactionUnderImport.m_strBrokerageAccount); } if (brokerageactid.isEmpty()) { brokerageactid = file->accountByName(statementTransactionUnderImport.m_strBrokerageAccount).id(); } // There is no BrokerageAccount so have to nowhere to put this split. if (!brokerageactid.isEmpty()) { sBrokerage.setMemo(statementTransactionUnderImport.m_strMemo); sBrokerage.setValue(transfervalue); sBrokerage.setShares(transfervalue); sBrokerage.setAccountId(brokerageactid); sBrokerage.setReconcileFlag(statementTransactionUnderImport.m_reconcile); MyMoneyAccount splitAccount = file->account(sBrokerage.accountId()); d->setupPrice(sBrokerage, splitAccount, d->m_account, statementTransactionUnderImport.m_datePosted); } } if (!(sBrokerage == MyMoneySplit())) transactionUnderImport.addSplit(sBrokerage); if (!(sFees == MyMoneySplit())) transactionUnderImport.addSplit(sFees); if (!(s2 == MyMoneySplit())) transactionUnderImport.addSplit(s2); transactionUnderImport.addSplit(s1); if ((statementTransactionUnderImport.m_eAction != MyMoneyStatement::Transaction::eaReinvestDividend) && (statementTransactionUnderImport.m_eAction != MyMoneyStatement::Transaction::eaCashDividend) && (statementTransactionUnderImport.m_eAction != MyMoneyStatement::Transaction::eaInterest) ) { //****************************************** // process splits //****************************************** QList::const_iterator it_s; for (it_s = statementTransactionUnderImport.m_listSplits.begin(); it_s != statementTransactionUnderImport.m_listSplits.end(); ++it_s) { MyMoneySplit s3; s3.setAccountId((*it_s).m_accountId); MyMoneyAccount acc = file->account(s3.accountId()); s3.setPayeeId(s1.payeeId()); s3.setMemo((*it_s).m_strMemo); s3.setShares((*it_s).m_amount); s3.setValue((*it_s).m_amount); s3.setReconcileFlag((*it_s).m_reconcile); d->setupPrice(s3, acc, d->m_account, statementTransactionUnderImport.m_datePosted); transactionUnderImport.addSplit(s3); } } // Add the transaction try { // check for matches already stored in the engine TransactionMatchFinder::MatchResult result; TransactionMatcher matcher(thisaccount); d->transactionsCount++; ExistingTransactionMatchFinder existingTrMatchFinder(KMyMoneyGlobalSettings::matchInterval()); result = existingTrMatchFinder.findMatch(transactionUnderImport, s1); if (result != TransactionMatchFinder::MatchNotFound) { MyMoneyTransaction matchedTransaction = existingTrMatchFinder.getMatchedTransaction(); if (!matchedTransaction.isImported() || result == TransactionMatchFinder::MatchPrecise) { // don't match with just imported transaction MyMoneySplit matchedSplit = existingTrMatchFinder.getMatchedSplit(); handleMatchingOfExistingTransaction(matcher, matchedTransaction, matchedSplit, transactionUnderImport, s1, result); return; } } addTransaction(transactionUnderImport); ScheduledTransactionMatchFinder scheduledTrMatchFinder(thisaccount, KMyMoneyGlobalSettings::matchInterval()); result = scheduledTrMatchFinder.findMatch(transactionUnderImport, s1); if (result != TransactionMatchFinder::MatchNotFound) { MyMoneySplit matchedSplit = scheduledTrMatchFinder.getMatchedSplit(); MyMoneySchedule matchedSchedule = scheduledTrMatchFinder.getMatchedSchedule(); handleMatchingOfScheduledTransaction(matcher, matchedSchedule, matchedSplit, transactionUnderImport, s1); return; } } catch (const MyMoneyException &e) { QString message(i18n("Problem adding or matching imported transaction with id '%1': %2", statementTransactionUnderImport.m_strBankID, e.what())); qDebug("%s", qPrintable(message)); int result = KMessageBox::warningContinueCancel(0, message); if (result == KMessageBox::Cancel) throw MYMONEYEXCEPTION("USERABORT"); } } QString MyMoneyStatementReader::SelectBrokerageAccount() { if (d->m_brokerageAccount.id().isEmpty()) { d->m_brokerageAccount.setAccountType(Account::Checkings); if (!m_userAbort) m_userAbort = ! selectOrCreateAccount(Select, d->m_brokerageAccount); } return d->m_brokerageAccount.id(); } bool MyMoneyStatementReader::selectOrCreateAccount(const SelectCreateMode /*mode*/, MyMoneyAccount& account) { bool result = false; MyMoneyFile* file = MyMoneyFile::instance(); QString accountId; // Try to find an existing account in the engine which matches this one. // There are two ways to be a "matching account". The account number can // match the statement account OR the "StatementKey" property can match. // Either way, we'll update the "StatementKey" property for next time. QString accountNumber = account.number(); if (! accountNumber.isEmpty()) { // Get a list of all accounts QList accounts; file->accountList(accounts); // Iterate through them QList::const_iterator it_account = accounts.constBegin(); while (it_account != accounts.constEnd()) { if ( ((*it_account).value("StatementKey") == accountNumber) || ((*it_account).number() == accountNumber) ) { MyMoneyAccount newAccount((*it_account).id(), account); account = newAccount; accountId = (*it_account).id(); break; } ++it_account; } } QString msg = i18n("You have downloaded a statement for the following account:

"); msg += i18n(" - Account Name: %1", account.name()) + "
"; msg += i18n(" - Account Type: %1", MyMoneyAccount::accountTypeToString(account.accountType())) + "
"; msg += i18n(" - Account Number: %1", account.number()) + "
"; msg += "
"; if (!account.name().isEmpty()) { if (!accountId.isEmpty()) msg += i18n("Do you want to import transactions to this account?"); else msg += i18n("KMyMoney cannot determine which of your accounts to use. You can " "create a new account by pressing the Create button " "or select another one manually from the selection box below."); } else { msg += i18n("No account information has been found in the selected statement file. " "Please select an account using the selection box in the dialog or " "create a new account by pressing the Create button."); } - KMyMoneyUtils::categoryTypeE type; + eDialogs::Category type; if (account.accountType() == Account::Checkings) { - type = static_cast(KMyMoneyUtils::checking); + type = eDialogs::Category::checking; } else if (account.accountType() == Account::Savings) { - type = static_cast(KMyMoneyUtils::savings); + type = eDialogs::Category::savings; } else if (account.accountType() == Account::Investment) { - type = static_cast(KMyMoneyUtils::investment); + type = eDialogs::Category::investment; } else if (account.accountType() == Account::CreditCard) { - type = static_cast(KMyMoneyUtils::creditCard); + type = eDialogs::Category::creditCard; } else { - type = static_cast(KMyMoneyUtils::asset | KMyMoneyUtils::liability); + type = static_cast(eDialogs::Category::asset | eDialogs::Category::liability); } QPointer accountSelect = new KAccountSelectDlg(type, "StatementImport", kmymoney); accountSelect->setHeader(i18n("Import transactions")); accountSelect->setDescription(msg); accountSelect->setAccount(account, accountId); accountSelect->setMode(false); accountSelect->showAbortButton(true); - accountSelect->m_qifEntry->hide(); + accountSelect->hideQifEntry(); QString accname; bool done = false; while (!done) { if (accountSelect->exec() == QDialog::Accepted && !accountSelect->selectedAccount().isEmpty()) { result = true; done = true; accountId = accountSelect->selectedAccount(); account = file->account(accountId); if (! accountNumber.isEmpty() && account.value("StatementKey") != accountNumber) { account.setValue("StatementKey", accountNumber); MyMoneyFileTransaction ft; try { MyMoneyFile::instance()->modifyAccount(account); ft.commit(); accname = account.name(); } catch (const MyMoneyException &) { qDebug("Updating account in MyMoneyStatementReader::selectOrCreateAccount failed"); } } } else { if (accountSelect->aborted()) //throw MYMONEYEXCEPTION("USERABORT"); done = true; else KMessageBox::error(0, QLatin1String("") + i18n("You must select an account, create a new one, or press the Abort button.") + QLatin1String("")); } } delete accountSelect; return result; } const MyMoneyAccount& MyMoneyStatementReader::account() const { return d->m_account; } void MyMoneyStatementReader::setProgressCallback(void(*callback)(int, int, const QString&)) { m_progressCallback = callback; } void MyMoneyStatementReader::signalProgress(int current, int total, const QString& msg) { if (m_progressCallback != 0) (*m_progressCallback)(current, total, msg); } void MyMoneyStatementReader::handleMatchingOfExistingTransaction(TransactionMatcher & matcher, MyMoneyTransaction matchedTransaction, MyMoneySplit matchedSplit, MyMoneyTransaction & importedTransaction, const MyMoneySplit & importedSplit, const TransactionMatchFinder::MatchResult & matchResult) { switch (matchResult) { case TransactionMatchFinder::MatchNotFound: break; case TransactionMatchFinder::MatchDuplicate: d->transactionsDuplicate++; qDebug("Detected transaction duplicate"); break; case TransactionMatchFinder::MatchImprecise: case TransactionMatchFinder::MatchPrecise: addTransaction(importedTransaction); qDebug("Detected as match to transaction '%s'", qPrintable(matchedTransaction.id())); matcher.match(matchedTransaction, matchedSplit, importedTransaction, importedSplit, true); d->transactionsMatched++; break; } } void MyMoneyStatementReader::handleMatchingOfScheduledTransaction(TransactionMatcher & matcher, MyMoneySchedule matchedSchedule, MyMoneySplit matchedSplit, const MyMoneyTransaction & importedTransaction, const MyMoneySplit & importedSplit) { QPointer editor; if (askUserToEnterScheduleForMatching(matchedSchedule, importedSplit, importedTransaction)) { KEnterScheduleDlg dlg(0, matchedSchedule); editor = dlg.startEdit(); if (editor) { MyMoneyTransaction torig; try { // in case the amounts of the scheduled transaction and the // imported transaction differ, we need to update the amount // using the transaction editor. if (matchedSplit.shares() != importedSplit.shares() && !matchedSchedule.isFixed()) { // for now this only works with regular transactions and not // for investment transactions. As of this, we don't have // scheduled investment transactions anyway. - StdTransactionEditor* se = dynamic_cast(editor.data()); + auto se = dynamic_cast(editor.data()); if (se) { // the following call will update the amount field in the // editor and also adjust a possible VAT assignment. Make // sure to use only the absolute value of the amount, because // the editor keeps the sign in a different position (deposit, // withdrawal tab) kMyMoneyEdit* amount = dynamic_cast(se->haveWidget("amount")); if (amount) { amount->setValue(importedSplit.shares().abs()); se->slotUpdateAmount(importedSplit.shares().abs().toString()); // we also need to update the matchedSplit variable to // have the modified share/value. matchedSplit.setShares(importedSplit.shares()); matchedSplit.setValue(importedSplit.value()); } } } editor->createTransaction(torig, dlg.transaction(), dlg.transaction().splits().isEmpty() ? MyMoneySplit() : dlg.transaction().splits().front(), true); QString newId; if (editor->enterTransactions(newId, false, true)) { if (!newId.isEmpty()) { torig = MyMoneyFile::instance()->transaction(newId); matchedSchedule.setLastPayment(torig.postDate()); } matchedSchedule.setNextDueDate(matchedSchedule.nextPayment(matchedSchedule.nextDueDate())); MyMoneyFile::instance()->modifySchedule(matchedSchedule); } // now match the two transactions matcher.match(torig, matchedSplit, importedTransaction, importedSplit); d->transactionsMatched++; } catch (const MyMoneyException &e) { // make sure we get rid of the editor before // the KEnterScheduleDlg is destroyed delete editor; throw e; // rethrow } } // delete the editor delete editor; } } void MyMoneyStatementReader::addTransaction(MyMoneyTransaction& transaction) { MyMoneyFile* file = MyMoneyFile::instance(); file->addTransaction(transaction); d->transactionsAdded++; } bool MyMoneyStatementReader::askUserToEnterScheduleForMatching(const MyMoneySchedule& matchedSchedule, const MyMoneySplit& importedSplit, const MyMoneyTransaction & importedTransaction) const { QString scheduleName = matchedSchedule.name(); int currencyDenom = d->m_account.fraction(MyMoneyFile::instance()->currency(d->m_account.currencyId())); QString splitValue = importedSplit.value().formatMoney(currencyDenom); QString payeeName = MyMoneyFile::instance()->payee(importedSplit.payeeId()).name(); QString questionMsg = i18n("KMyMoney has found a scheduled transaction which matches an imported transaction.
" "Schedule name: %1
" "Transaction: %2 %3
" "Do you want KMyMoney to enter this schedule now so that the transaction can be matched?", scheduleName, splitValue, payeeName); // check that dates are within user's setting const int gap = std::abs(matchedSchedule.transaction().postDate().toJulianDay() - importedTransaction.postDate().toJulianDay()); if (gap > KMyMoneyGlobalSettings::matchInterval()) questionMsg = i18np("KMyMoney has found a scheduled transaction which matches an imported transaction.
" "Schedule name: %2
" "Transaction: %3 %4
" "The transaction dates are one day apart.
" "Do you want KMyMoney to enter this schedule now so that the transaction can be matched?", "KMyMoney has found a scheduled transaction which matches an imported transaction.
" "Schedule name: %2
" "Transaction: %3 %4
" "The transaction dates are %1 days apart.
" "Do you want KMyMoney to enter this schedule now so that the transaction can be matched?", gap ,scheduleName, splitValue, payeeName); const int userAnswer = KMessageBox::questionYesNo(0, QLatin1String("") + questionMsg + QLatin1String(""), i18n("Schedule found")); return (userAnswer == KMessageBox::Yes); } diff --git a/kmymoney/dialogs/CMakeLists.txt b/kmymoney/dialogs/CMakeLists.txt index b97119edb..49470ca3a 100644 --- a/kmymoney/dialogs/CMakeLists.txt +++ b/kmymoney/dialogs/CMakeLists.txt @@ -1,111 +1,112 @@ add_subdirectory( settings ) ########### next target ############### set(libdialogs_a_SOURCES splitadjustdialog.cpp investactivities.cpp investtransactioneditor.cpp kaccountselectdlg.cpp kbackupdlg.cpp kbalancechartdlg.cpp kbalancewarning.cpp kcategoryreassigndlg.cpp kchooseimportexportdlg.cpp kconfirmmanualenterdlg.cpp kcurrencycalculator.cpp kcurrencyeditdlg.cpp kavailablecurrencydlg.cpp kcurrencyeditordlg.cpp keditscheduledlg.cpp kenterscheduledlg.cpp kequitypriceupdatedlg.cpp kequitypriceupdateconfdlg.cpp kfindtransactiondlg.cpp kgeneratesqldlg.cpp kgncimportoptionsdlg.cpp kgncpricesourcedlg.cpp kgpgkeyselectiondlg.cpp kloadtemplatedlg.cpp kmergetransactionsdlg.cpp kmymoneyfileinfodlg.cpp kmymoneypricedlg.cpp kmymoneysplittable.cpp knewaccountdlg.cpp hierarchyfilterproxymodel.cpp knewbankdlg.cpp knewbudgetdlg.cpp knewequityentrydlg.cpp editpersonaldatadlg.cpp kpayeereassigndlg.cpp ktagreassigndlg.cpp kreportconfigurationfilterdlg.cpp kselectdatabasedlg.cpp kselecttransactionsdlg.cpp ksplittransactiondlg.cpp ktemplateexportdlg.cpp kupdatestockpricedlg.cpp transactioneditor.cpp + stdtransactioneditor.cpp transactionmatcher.cpp konlinetransferform.cpp ) set(dialogs_HEADERS splitadjustdialog.h - investtransactioneditor.h kcurrencycalculator.h transactioneditor.h + investtransactioneditor.h kcurrencycalculator.h transactioneditor.h stdtransactioneditor.h ) set(dialogs_UI splitadjustdialog.ui - kaccountselectdlgdecl.ui kbackupdlgdecl.ui - kcategoryreassigndlgdecl.ui kchooseimportexportdlgdecl.ui - kconfirmmanualenterdlgdecl.ui - kcurrencycalculatordecl.ui kcurrencyeditdlg.ui kavailablecurrencydlg.ui kcurrencyeditordlg.ui - keditscheduledlgdecl.ui - kenterscheduledlgdecl.ui - kequitypriceupdatedlgdecl.ui kequitypriceupdateconfdlg.ui - kfindtransactiondlgdecl.ui kgeneratesqldlgdecl.ui kgncimportoptionsdlgdecl.ui - kgncpricesourcedlgdecl.ui kloadtemplatedlgdecl.ui - kmymoneyfileinfodlgdecl.ui kmymoneypricedlgdecl.ui - knewaccountdlg.ui knewbankdlgdecl.ui knewbudgetdlgdecl.ui - knewequityentrydecl.ui editpersonaldatadlgdecl.ui kpayeereassigndlgdecl.ui - ktagreassigndlgdecl.ui - kselectdatabasedlg.ui kselecttransactionsdlgdecl.ui - ksortoptiondlg.ui ksplitcorrectiondlg.ui ksplittransactiondlgdecl.ui + kaccountselectdlg.ui kbackupdlg.ui + kcategoryreassigndlg.ui kchooseimportexportdlg.ui + kconfirmmanualenterdlg.ui + kcurrencycalculator.ui kcurrencyeditdlg.ui kavailablecurrencydlg.ui kcurrencyeditordlg.ui + keditscheduledlg.ui + kenterscheduledlg.ui + kequitypriceupdatedlg.ui kequitypriceupdateconfdlg.ui + kfindtransactiondlg.ui kgeneratesqldlg.ui kgncimportoptionsdlg.ui + kgncpricesourcedlg.ui kloadtemplatedlg.ui + kmymoneyfileinfodlg.ui kmymoneypricedlg.ui + knewaccountdlg.ui knewbankdlg.ui knewbudgetdlg.ui + knewequityentrydlg.ui editpersonaldatadlg.ui kpayeereassigndlg.ui + ktagreassigndlg.ui + kselectdatabasedlg.ui kselecttransactionsdlg.ui + ksortoptiondlg.ui ksplitcorrectiondlg.ui ksplittransactiondlg.ui ktemplateexportdlg.ui - kupdatestockpricedlgdecl.ui + kupdatestockpricedlg.ui ../widgets/kaccounttemplateselectordecl.ui ../widgets/transactionsortoptiondecl.ui - konlinetransferformdecl.ui + konlinetransferform.ui ) ki18n_wrap_ui(libdialogs_a_SOURCES ${dialogs_UI} ) add_library(dialogs STATIC ${libdialogs_a_SOURCES}) target_link_libraries(dialogs PUBLIC KChart KF5::ItemViews KF5::I18n KF5::TextWidgets KF5::Completion Qt5::Widgets Qt5::Sql Alkimia::alkimia kmm_mymoney onlinetask_interfaces kmm_widgets kmm_utils_platformtools ) target_link_libraries(dialogs LINK_PUBLIC kmm_widgets kmm_mymoney onlinetask_interfaces ) ########### install files ############### install(FILES ${dialogs_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/kmymoney COMPONENT Devel) diff --git a/kmymoney/dialogs/dialogenums.h b/kmymoney/dialogs/dialogenums.h new file mode 100644 index 000000000..b274dc86c --- /dev/null +++ b/kmymoney/dialogs/dialogenums.h @@ -0,0 +1,65 @@ +/*************************************************************************** + dialogenums.h + ------------------- + copyright : (C) 2017 by Ł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. * + * * + ***************************************************************************/ + +#ifndef DIALOGENUMS_H +#define DIALOGENUMS_H + +namespace eDialogs { + /** + * This enum is used to describe the bits of an account type filter mask. + * Each bit is used to define a specific account class. Multiple classes + * can be specified by OR'ing multiple entries. The special entry @p last + * marks the left most bit in the mask and is used by scanners of this + * bitmask to determine the end of processing. + */ + enum Category : int { + none = 0x000, ///< no account class selected + liability = 0x001, ///< liability accounts selected + asset = 0x002, ///< asset accounts selected + expense = 0x004, ///< expense accounts selected + income = 0x008, ///< income accounts selected + equity = 0x010, ///< equity accounts selected + checking = 0x020, ///< checking accounts selected + savings = 0x040, ///< savings accounts selected + investment = 0x080, ///< investment accounts selected + creditCard = 0x100, ///< credit card accounts selected + last = 0x200 ///< the leftmost bit in the mask + }; + + enum class UpdatePrice { + All = 0, + Missing, + Downloaded, + SameSource, + Ask + }; + + enum class PriceMode { + Price = 0, + PricePerShare, + PricePerTransaction + }; + + enum class ScheduleResultCode { + Cancel = 0, // cancel the operation + Enter, // enter the schedule + Skip, // skip the schedule + Ignore // ignore the schedule + }; + +} + +#endif diff --git a/kmymoney/dialogs/editpersonaldatadlg.cpp b/kmymoney/dialogs/editpersonaldatadlg.cpp index 3255d524e..2affaa08b 100644 --- a/kmymoney/dialogs/editpersonaldatadlg.cpp +++ b/kmymoney/dialogs/editpersonaldatadlg.cpp @@ -1,125 +1,205 @@ /*************************************************************************** knewfiledlg.cpp ------------------- copyright : (C) 2000 by Michael Edwardes email : mte@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "editpersonaldatadlg.h" // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Headers #include #include // ---------------------------------------------------------------------------- // Project Includes #include "mymoneycontact.h" -#include "ui_editpersonaldatadlgdecl.h" +#include "ui_editpersonaldatadlg.h" -struct EditPersonalDataDlg::Private { - Private() : m_contact(0) {} - Ui::EditPersonalDataDlgDecl ui; - MyMoneyContact *m_contact; +class EditPersonalDataDlgPrivate +{ + Q_DISABLE_COPY(EditPersonalDataDlgPrivate) + Q_DECLARE_PUBLIC(EditPersonalDataDlg) + +public: + EditPersonalDataDlgPrivate(EditPersonalDataDlg *qq) : + q_ptr(qq), + ui(new Ui::EditPersonalDataDlg) + { + } + + ~EditPersonalDataDlgPrivate() + { + delete m_contact; + delete ui; + } + + void init(const QString& title) + { + Q_Q(EditPersonalDataDlg); + m_contact = new MyMoneyContact(q); + ui->setupUi(q); + q->setModal(true); + + if (!title.isEmpty()) + q->setWindowTitle(title); + + ui->kabcBtn->setEnabled(m_contact->ownerExists()); + ui->userNameEdit->setFocus(); + + q->connect(ui->buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject); + q->connect(ui->buttonBox, &QDialogButtonBox::accepted, q, &EditPersonalDataDlg::okClicked); + q->connect(ui->kabcBtn, &QAbstractButton::clicked, q, &EditPersonalDataDlg::loadFromAddressBook); + } + + EditPersonalDataDlg *q_ptr; + Ui::EditPersonalDataDlg *ui; + MyMoneyContact *m_contact; + QString userNameText; + QString userStreetText; + QString userTownText; + QString userCountyText; + QString userPostcodeText; + QString userTelephoneText; + QString userEmailText; }; -EditPersonalDataDlg::EditPersonalDataDlg(QWidget *parent, const QString& title) - : QDialog(parent), d(new Private) + +EditPersonalDataDlg::EditPersonalDataDlg(QWidget *parent, const QString& title) : + QDialog(parent), + d_ptr(new EditPersonalDataDlgPrivate(this)) { - d->m_contact = new MyMoneyContact(this); - d->ui.setupUi(this); - setModal(true); - init(title); + Q_D(EditPersonalDataDlg); + d->init(title); } -EditPersonalDataDlg::EditPersonalDataDlg(QString userName, QString userStreet, - QString userTown, QString userCounty, QString userPostcode, QString userTelephone, - QString userEmail, QWidget *parent, const QString& title) - : QDialog(parent), d(new Private) +EditPersonalDataDlg::EditPersonalDataDlg(QString userName, + QString userStreet, + QString userTown, + QString userCounty, + QString userPostcode, + QString userTelephone, + QString userEmail, + QWidget *parent, + const QString& title) : + QDialog(parent), + d_ptr(new EditPersonalDataDlgPrivate(this)) { - d->m_contact = new MyMoneyContact(this); - d->ui.setupUi(this); - setModal(true); - d->ui.userNameEdit->setText(userName); - d->ui.streetEdit->setText(userStreet); - d->ui.townEdit->setText(userTown); - d->ui.countyEdit->setText(userCounty); - d->ui.postcodeEdit->setText(userPostcode); - d->ui.telephoneEdit->setText(userTelephone); - d->ui.emailEdit->setText(userEmail); - - init(title); + Q_D(EditPersonalDataDlg); + d->init(title); + d->ui->userNameEdit->setText(userName); + d->ui->streetEdit->setText(userStreet); + d->ui->townEdit->setText(userTown); + d->ui->countyEdit->setText(userCounty); + d->ui->postcodeEdit->setText(userPostcode); + d->ui->telephoneEdit->setText(userTelephone); + d->ui->emailEdit->setText(userEmail); } -void EditPersonalDataDlg::init(const QString& title) +QString EditPersonalDataDlg::userName() const { - if (!title.isEmpty()) - setWindowTitle(title); + Q_D(const EditPersonalDataDlg); + return d->userNameText; +} - d->ui.kabcBtn->setEnabled(d->m_contact->ownerExists()); - d->ui.userNameEdit->setFocus(); +QString EditPersonalDataDlg::userStreet() const +{ + Q_D(const EditPersonalDataDlg); + return d->userStreetText; +} - connect(d->ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - connect(d->ui.buttonBox, SIGNAL(accepted()), this, SLOT(okClicked())); - connect(d->ui.kabcBtn, SIGNAL(clicked()), this, SLOT(loadFromAddressBook())); +QString EditPersonalDataDlg::userTown() const +{ + Q_D(const EditPersonalDataDlg); + return d->userTownText; +} + +QString EditPersonalDataDlg::userCountry() const +{ + Q_D(const EditPersonalDataDlg); + return d->userCountyText; +} + +QString EditPersonalDataDlg::userPostcode() const +{ + Q_D(const EditPersonalDataDlg); + return d->userPostcodeText; +} + +QString EditPersonalDataDlg::userTelephone() const +{ + Q_D(const EditPersonalDataDlg); + return d->userTelephoneText; +} + +QString EditPersonalDataDlg::userEmail() const +{ + Q_D(const EditPersonalDataDlg); + return d->userEmailText; } EditPersonalDataDlg::~EditPersonalDataDlg() { + Q_D(EditPersonalDataDlg); delete d; } void EditPersonalDataDlg::okClicked() { - userNameText = d->ui.userNameEdit->text(); - userStreetText = d->ui.streetEdit->text(); - userTownText = d->ui.townEdit->text(); - userCountyText = d->ui.countyEdit->text(); - userPostcodeText = d->ui.postcodeEdit->text(); - userTelephoneText = d->ui.telephoneEdit->text(); - userEmailText = d->ui.emailEdit->text(); + Q_D(EditPersonalDataDlg); + d->userNameText = d->ui->userNameEdit->text(); + d->userStreetText = d->ui->streetEdit->text(); + d->userTownText = d->ui->townEdit->text(); + d->userCountyText = d->ui->countyEdit->text(); + d->userPostcodeText = d->ui->postcodeEdit->text(); + d->userTelephoneText = d->ui->telephoneEdit->text(); + d->userEmailText = d->ui->emailEdit->text(); accept(); } void EditPersonalDataDlg::loadFromAddressBook() { - d->ui.userNameEdit->setText(d->m_contact->ownerFullName()); - d->ui.emailEdit->setText(d->m_contact->ownerEmail()); - if (d->ui.emailEdit->text().isEmpty()) { + Q_D(EditPersonalDataDlg); + d->ui->userNameEdit->setText(d->m_contact->ownerFullName()); + d->ui->emailEdit->setText(d->m_contact->ownerEmail()); + if (d->ui->emailEdit->text().isEmpty()) { KMessageBox::sorry(this, i18n("Unable to load data, because no contact has been associated with the owner of the standard address book."), i18n("Address book import")); return; } - d->ui.kabcBtn->setEnabled(false); - connect(d->m_contact, SIGNAL(contactFetched(ContactData)), this, SLOT(slotContactFetched(ContactData))); - d->m_contact->fetchContact(d->ui.emailEdit->text()); + d->ui->kabcBtn->setEnabled(false); + connect(d->m_contact, &MyMoneyContact::contactFetched, this, &EditPersonalDataDlg::slotContactFetched); + d->m_contact->fetchContact(d->ui->emailEdit->text()); } void EditPersonalDataDlg::slotContactFetched(const ContactData &identity) { - d->ui.telephoneEdit->setText(identity.phoneNumber); + Q_D(EditPersonalDataDlg); + d->ui->telephoneEdit->setText(identity.phoneNumber); QString sep; if (!identity.country.isEmpty() && !identity.region.isEmpty()) sep = " / "; - d->ui.countyEdit->setText(QString("%1%2%3").arg(identity.country, sep, identity.region)); - d->ui.postcodeEdit->setText(identity.postalCode); - d->ui.townEdit->setText(identity.locality); - d->ui.streetEdit->setText(identity.street); - d->ui.kabcBtn->setEnabled(true); + d->ui->countyEdit->setText(QString("%1%2%3").arg(identity.country, sep, identity.region)); + d->ui->postcodeEdit->setText(identity.postalCode); + d->ui->townEdit->setText(identity.locality); + d->ui->streetEdit->setText(identity.street); + d->ui->kabcBtn->setEnabled(true); } diff --git a/kmymoney/dialogs/editpersonaldatadlg.h b/kmymoney/dialogs/editpersonaldatadlg.h index 3894220d4..415c121cb 100644 --- a/kmymoney/dialogs/editpersonaldatadlg.h +++ b/kmymoney/dialogs/editpersonaldatadlg.h @@ -1,71 +1,74 @@ /*************************************************************************** knewfiledlg.h ------------------- copyright : (C) 2000 by Michael Edwardes email : mte@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ -#ifndef KNEWFILEDLG_H -#define KNEWFILEDLG_H +#ifndef EDITPERSONALDATADLG_H +#define EDITPERSONALDATADLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes struct ContactData; // This dialog lets the user create/edit a file. // Use the second constructor to edit a file. +class EditPersonalDataDlgPrivate; class EditPersonalDataDlg : public QDialog { Q_OBJECT -public: - explicit EditPersonalDataDlg(QWidget *parent = 0, const QString& title = QString()); - explicit EditPersonalDataDlg(QString userName, QString userStreet, - QString userTown, QString userCounty, QString userPostcode, QString userTelephone, - QString userEmail, QWidget *parent = 0, const QString& title = QString()); - ~EditPersonalDataDlg(); + Q_DISABLE_COPY(EditPersonalDataDlg) public: - QString userNameText; - QString userStreetText; - QString userTownText; - QString userCountyText; - QString userPostcodeText; - QString userTelephoneText; - QString userEmailText; + explicit EditPersonalDataDlg(QWidget *parent, const QString& title); + explicit EditPersonalDataDlg(QString userName, + QString userStreet, + QString userTown, + QString userCounty, + QString userPostcode, + QString userTelephone, + QString userEmail, + QWidget *parent, + const QString& title); + ~EditPersonalDataDlg(); -protected: - /// helper method for constructors - void init(const QString& title); + QString userName() const; + QString userStreet() const; + QString userTown() const; + QString userCountry() const; + QString userPostcode() const; + QString userTelephone() const; + QString userEmail() const; protected slots: void okClicked(); void loadFromAddressBook(); /** Gets the result of searching for the contact details of the current user */ void slotContactFetched(const ContactData &identity); private: - /// \internal d-pointer class. - struct Private; - /// \internal d-pointer instance. - Private* const d; + EditPersonalDataDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(EditPersonalDataDlg) }; #endif diff --git a/kmymoney/dialogs/editpersonaldatadlgdecl.ui b/kmymoney/dialogs/editpersonaldatadlg.ui similarity index 98% rename from kmymoney/dialogs/editpersonaldatadlgdecl.ui rename to kmymoney/dialogs/editpersonaldatadlg.ui index 5194064db..e142c65d9 100644 --- a/kmymoney/dialogs/editpersonaldatadlgdecl.ui +++ b/kmymoney/dialogs/editpersonaldatadlg.ui @@ -1,283 +1,283 @@ - EditPersonalDataDlgDecl - + EditPersonalDataDlg + 0 0 546 - 448 + 461 New File Dialog true 6 11 11 11 11 6 0 0 0 0 Use this dialog to enter personal information about yourself. All information is optional and is provided to personalize your KMyMoney file. false QFrame::HLine QFrame::Raised 1 100 0 County/State: false 100 0 Street: false 100 0 Email: false Your name: false 100 0 Telephone: false 100 0 Town: false 100 0 Postal Code: false Load from Addressbook Qt::Horizontal QSizePolicy::Expanding 305 21 Qt::Vertical QSizePolicy::Expanding 20 16 QDialogButtonBox::Cancel|QDialogButtonBox::Ok KLineEdit QLineEdit
klineedit.h
userNameEdit streetEdit townEdit countyEdit postcodeEdit telephoneEdit emailEdit kabcBtn
diff --git a/kmymoney/dialogs/hierarchyfilterproxymodel.h b/kmymoney/dialogs/hierarchyfilterproxymodel.h index b3ce5226e..c9c2fd7ba 100644 --- a/kmymoney/dialogs/hierarchyfilterproxymodel.h +++ b/kmymoney/dialogs/hierarchyfilterproxymodel.h @@ -1,55 +1,55 @@ /*************************************************************************** hierarchyfilterproxymodel.h ------------------- copyright : (C) 2000 by Michael Edwardes (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef HIERARCHYFILTERPROXYMODEL_H #define HIERARCHYFILTERPROXYMODEL_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Headers // ---------------------------------------------------------------------------- // Project Includes #include "accountsproxymodel.h" class HierarchyFilterProxyModel : public AccountsProxyModel { Q_OBJECT public: - HierarchyFilterProxyModel(QObject *parent = 0); + HierarchyFilterProxyModel(QObject *parent = nullptr); Qt::ItemFlags flags(const QModelIndex &index) const override; void setCurrentAccountId(const QString &selectedAccountId); QModelIndex getSelectedParentAccountIndex() const; protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const override; private: QString m_currentAccountId; }; #endif diff --git a/kmymoney/dialogs/investactivities.cpp b/kmymoney/dialogs/investactivities.cpp index 19519b665..a1c11f565 100644 --- a/kmymoney/dialogs/investactivities.cpp +++ b/kmymoney/dialogs/investactivities.cpp @@ -1,736 +1,939 @@ /*************************************************************************** investactivities.cpp ---------- begin : Fri Dec 15 2006 copyright : (C) 2006 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "investactivities.h" // ---------------------------------------------------------------------------- // QT Includes #include #include // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes +#include "investtransactioneditor.h" +#include "mymoneymoney.h" #include "kmymoneycategory.h" #include "kmymoneyedit.h" #include "kmymoneyaccountselector.h" #include "kmymoneycompletion.h" #include #include "mymoneyfile.h" +#include "mymoneysplit.h" +#include "mymoneyaccount.h" +#include "mymoneysecurity.h" +#include "dialogenums.h" +#include "mymoneyenums.h" using namespace Invest; using namespace KMyMoneyRegister; +class Invest::ActivityPrivate +{ + Q_DISABLE_COPY(ActivityPrivate) + +public: + ActivityPrivate() + { + } + + InvestTransactionEditor *m_parent; + QMap m_priceInfo; + bool m_memoChanged; + QString m_memoText; +}; + + +Activity::Activity(InvestTransactionEditor* editor) : + d_ptr(new ActivityPrivate) +{ + Q_D(Activity); + d->m_memoChanged = false; + d->m_parent = editor; +} + +Activity::~Activity() +{ + Q_D(Activity); + delete d; +} + +bool& Activity::memoChanged() +{ + Q_D(Activity); + return d->m_memoChanged; +} + +QString& Activity::memoText() +{ + Q_D(Activity); + return d->m_memoText; +} + bool Activity::isComplete(QString& reason) const { + Q_D(const Activity); Q_UNUSED(reason) - bool rc = false; - KMyMoneySecurity* security = dynamic_cast(haveWidget("security")); + auto rc = false; + auto security = dynamic_cast(haveWidget("security")); if (!security->currentText().isEmpty()) { - rc = (security->selector()->contains(security->currentText()) || (isMultiSelection() && m_memoChanged)); + rc = (security->selector()->contains(security->currentText()) || (isMultiSelection() && d->m_memoChanged)); } return rc; } +QWidget* Activity::haveWidget(const QString& name) const +{ + Q_D(const Activity); + return d->m_parent->haveWidget(name); +} + bool Activity::haveAssetAccount() const { - KMyMoneyCategory* cat = dynamic_cast(haveWidget("asset-account")); + auto cat = dynamic_cast(haveWidget("asset-account")); - bool rc = true; + auto rc = true; if (!isMultiSelection()) rc = !cat->currentText().isEmpty(); if (rc && !cat->currentText().isEmpty()) { rc = cat->selector()->contains(cat->currentText()); } return rc; } bool Activity::haveCategoryAndAmount(const QString& category, const QString& amount, bool optional) const { - KMyMoneyCategory* cat = dynamic_cast(haveWidget(category)); + Q_D(const Activity); + auto cat = dynamic_cast(haveWidget(category)); - bool rc = true; + auto rc = true; if (!cat->currentText().isEmpty()) { rc = cat->selector()->contains(cat->currentText()) || cat->isSplitTransaction(); if (rc && !amount.isEmpty() && !isMultiSelection()) { if (cat->isSplitTransaction()) { QList::const_iterator split; QList::const_iterator splitEnd; if (category == "fee-account") { - split = m_parent->feeSplits().cbegin(); - splitEnd = m_parent->feeSplits().cend(); + split = d->m_parent->feeSplits().cbegin(); + splitEnd = d->m_parent->feeSplits().cend(); } else if (category == "interest-account") { - split = m_parent->interestSplits().cbegin(); - splitEnd = m_parent->interestSplits().cend(); + split = d->m_parent->interestSplits().cbegin(); + splitEnd = d->m_parent->interestSplits().cend(); } for (; split != splitEnd; ++split) { if ((*split).value().isZero()) rc = false; } } else { MyMoneyMoney value = dynamic_cast(haveWidget(amount))->value(); rc = !value.isZero(); } } } else if (!isMultiSelection() && !optional) { rc = false; } return rc; } +bool Activity::haveFees(bool optional) const +{ + return haveCategoryAndAmount("fee-account", "fee-amount", optional); +} + +bool Activity::haveInterest(bool optional) const +{ + return haveCategoryAndAmount("interest-account", "interest-amount", optional); +} + bool Activity::haveShares() const { kMyMoneyEdit* amount = dynamic_cast(haveWidget("shares")); if (isMultiSelection() && amount->value().isZero()) return true; return !amount->value().isZero(); } bool Activity::havePrice() const { kMyMoneyEdit* amount = dynamic_cast(haveWidget("price")); if (isMultiSelection() && amount->value().isZero()) return true; return !amount->value().isZero(); } +bool Activity::isMultiSelection() const +{ + Q_D(const Activity); + return d->m_parent->isMultiSelection(); +} + bool Activity::createCategorySplits(const MyMoneyTransaction& t, KMyMoneyCategory* cat, kMyMoneyEdit* amount, MyMoneyMoney factor, QList&splits, const QList& osplits) const { - bool rc = true; + Q_D(const Activity); + auto rc = true; if (!isMultiSelection() || (isMultiSelection() && !cat->currentText().isEmpty())) { if (!cat->isSplitTransaction()) { splits.clear(); MyMoneySplit s1; QString categoryId; categoryId = cat->selectedItem(); if (!categoryId.isEmpty()) { s1.setAccountId(categoryId); s1.setValue(amount->value() * factor); if (!s1.value().isZero()) { - rc = m_parent->setupPrice(t, s1); + rc = d->m_parent->setupPrice(t, s1); } splits.append(s1); } } else { splits = osplits; } } return rc; } void Activity::createAssetAccountSplit(MyMoneySplit& split, const MyMoneySplit& stockSplit) const { - KMyMoneyCategory* cat = dynamic_cast(haveWidget("asset-account")); + auto cat = dynamic_cast(haveWidget("asset-account")); if (!isMultiSelection() || (isMultiSelection() && !cat->currentText().isEmpty())) { QString categoryId; categoryId = cat->selectedItem(); split.setAccountId(categoryId); } split.setMemo(stockSplit.memo()); } MyMoneyMoney Activity::sumSplits(const MyMoneySplit& s0, const QList& feeSplits, const QList& interestSplits) const { MyMoneyMoney total; total = s0.value(); QList::const_iterator it_s; for (it_s = feeSplits.begin(); it_s != feeSplits.end(); ++it_s) { total += (*it_s).value(); } for (it_s = interestSplits.begin(); it_s != interestSplits.end(); ++it_s) { total += (*it_s).value(); } return total; } void Activity::setLabelText(const QString& idx, const QString& txt) const { - QLabel* w = dynamic_cast(haveWidget(idx)); + auto w = dynamic_cast(haveWidget(idx)); if (w) { w->setText(txt); } else { if (KMyMoneySettings::transactionForm()) { // labels are only used in the transaction form qDebug("Unknown QLabel named '%s'", qPrintable(idx)); } } } void Activity::preloadAssetAccount() { + Q_D(Activity); KMyMoneyCategory* cat; cat = dynamic_cast(haveWidget("asset-account")); if (cat->isVisible()) { if (cat->currentText().isEmpty()) { - MyMoneyAccount acc = MyMoneyFile::instance()->accountByName(i18n("%1 (Brokerage)", m_parent->account().name())); + MyMoneyAccount acc = MyMoneyFile::instance()->accountByName(i18n("%1 (Brokerage)", d->m_parent->account().name())); if (!acc.id().isEmpty()) { bool blocked = cat->signalsBlocked(); // block signals, so that the focus does not go crazy cat->blockSignals(true); cat->completion()->setSelected(acc.id()); cat->slotItemSelected(acc.id()); cat->blockSignals(blocked); } } } } void Activity::setWidgetVisibility(const QStringList& widgetIds, bool visible) const { for (QStringList::const_iterator it_w = widgetIds.constBegin(); it_w != widgetIds.constEnd(); ++it_w) { - QWidget* w = haveWidget(*it_w); + auto w = haveWidget(*it_w); if (w) { if (visible) { w->show(); } else { w->hide(); } } } } +eDialogs::PriceMode Activity::priceMode() const +{ + Q_D(const Activity); + return d->m_parent->priceMode(); +} + QString Activity::priceLabel() const { QString label; - if (priceMode() == InvestTransactionEditor::Price) { + if (priceMode() == eDialogs::PriceMode::Price) { label = i18n("Price"); - } else if (priceMode() == InvestTransactionEditor::PricePerShare) { + } else if (priceMode() == eDialogs::PriceMode::PricePerShare) { label = i18n("Price/share"); - } else if (priceMode() == InvestTransactionEditor::PricePerTransaction) { + } else if (priceMode() == eDialogs::PriceMode::PricePerTransaction) { label = i18n("Transaction amount"); } return label; } +Buy::Buy(InvestTransactionEditor* editor) : + Activity(editor) +{ +} + +Buy::~Buy() +{ +} + +eMyMoney::Split::InvestmentTransactionType Buy::type() const +{ + return eMyMoney::Split::InvestmentTransactionType::BuyShares; +} + void Buy::showWidgets() const { static const QStringList visibleWidgetIds = QStringList() << "asset-account" << "shares" << "price" << "total" << "interest-account" << "fee-account"; setWidgetVisibility(visibleWidgetIds, true); setLabelText("interest-amount-label", i18n("Interest")); setLabelText("interest-label", i18n("Interest")); setLabelText("fee-label", i18n("Fees")); setLabelText("asset-label", i18n("Account")); setLabelText("shares-label", i18n("Shares")); if (dynamic_cast(haveWidget("price-label"))) setLabelText("price-label", priceLabel()); setLabelText("total-label", i18nc("Total value", "Total")); } bool Buy::isComplete(QString& reason) const { - bool rc = Activity::isComplete(reason); + auto rc = Activity::isComplete(reason); rc &= haveAssetAccount(); rc &= haveFees(true); rc &= haveShares(); rc &= havePrice(); return rc; } bool Buy::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) { + Q_D(Activity); Q_UNUSED(m_interestSplits); Q_UNUSED(security); Q_UNUSED(currency); QString reason; if (!isComplete(reason)) return false; - kMyMoneyEdit* sharesEdit = dynamic_cast(haveWidget("shares")); - kMyMoneyEdit* priceEdit = dynamic_cast(haveWidget("price")); + auto sharesEdit = dynamic_cast(haveWidget("shares")); + auto priceEdit = dynamic_cast(haveWidget("price")); s0.setAction(eMyMoney::Split::InvestmentTransactionType::BuyShares); MyMoneyMoney shares = s0.shares(); MyMoneyMoney price; if (!s0.shares().isZero()) price = (s0.value() / s0.shares()).reduce(); if (!isMultiSelection() || (isMultiSelection() && !sharesEdit->value().isZero())) { shares = sharesEdit->value().abs(); s0.setShares(shares); s0.setValue((shares * price).reduce()); s0.setPrice(price); } if (!isMultiSelection() || (isMultiSelection() && !priceEdit->value().isZero())) { price = priceEdit->value().abs(); - if (priceMode() == InvestTransactionEditor::PricePerTransaction) { + if (priceMode() == eDialogs::PriceMode::PricePerTransaction) { s0.setValue(price.reduce()); if (!s0.shares().isZero()) s0.setPrice((price / s0.shares()).reduce()); } else { s0.setValue((shares * price).reduce()); s0.setPrice(price); } } if (!createCategorySplits(t, dynamic_cast(haveWidget("fee-account")), dynamic_cast(haveWidget("fee-amount")), MyMoneyMoney::ONE, feeSplits, m_feeSplits)) return false; createAssetAccountSplit(assetAccountSplit, s0); MyMoneyMoney total = sumSplits(s0, feeSplits, QList()); // Clear any leftover value from previous Dividend. interestSplits.clear(); assetAccountSplit.setValue(-total); - if (!m_parent->setupPrice(t, assetAccountSplit)) + if (!d->m_parent->setupPrice(t, assetAccountSplit)) return false; return true; } +Sell::Sell(InvestTransactionEditor* editor) : + Activity(editor) +{ +} + +Sell::~Sell() +{ +} + +eMyMoney::Split::InvestmentTransactionType Sell::type() const +{ + return eMyMoney::Split::InvestmentTransactionType::SellShares; +} + void Sell::showWidgets() const { + Q_D(const Activity); static const QStringList visibleWidgetIds = QStringList() << "asset-account" << "interest-amount" << "shares" << "price" << "total" << "interest-account" << "fee-account"; setWidgetVisibility(visibleWidgetIds, true); - kMyMoneyEdit* shareEdit = dynamic_cast(haveWidget("shares")); - shareEdit->setPrecision(MyMoneyMoney::denomToPrec(m_parent->security().smallestAccountFraction())); + auto shareEdit = dynamic_cast(haveWidget("shares")); + shareEdit->setPrecision(MyMoneyMoney::denomToPrec(d->m_parent->security().smallestAccountFraction())); setLabelText("interest-amount-label", i18n("Interest")); setLabelText("interest-label", i18n("Interest")); setLabelText("fee-label", i18n("Fees")); setLabelText("asset-label", i18n("Account")); setLabelText("shares-label", i18n("Shares")); if (dynamic_cast(haveWidget("price-label"))) setLabelText("price-label", priceLabel()); setLabelText("total-label", i18nc("Total value", "Total")); } bool Sell::isComplete(QString& reason) const { - bool rc = Activity::isComplete(reason); + auto rc = Activity::isComplete(reason); rc &= haveAssetAccount(); rc &= haveFees(true); rc &= haveInterest(true); rc &= haveShares(); rc &= havePrice(); return rc; } bool Sell::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) { + Q_D(Activity); Q_UNUSED(m_interestSplits); Q_UNUSED(security); Q_UNUSED(currency); QString reason; if (!isComplete(reason)) return false; - kMyMoneyEdit* sharesEdit = dynamic_cast(haveWidget("shares")); - kMyMoneyEdit* priceEdit = dynamic_cast(haveWidget("price")); + auto sharesEdit = dynamic_cast(haveWidget("shares")); + auto priceEdit = dynamic_cast(haveWidget("price")); s0.setAction(eMyMoney::Split::InvestmentTransactionType::BuyShares); MyMoneyMoney shares = s0.shares(); MyMoneyMoney price; if (!s0.shares().isZero()) price = (s0.value() / s0.shares()).reduce(); if (!isMultiSelection() || (isMultiSelection() && !sharesEdit->value().isZero())) { shares = -sharesEdit->value().abs(); s0.setShares(shares); s0.setValue((shares * price).reduce()); s0.setPrice(price); } if (!isMultiSelection() || (isMultiSelection() && !priceEdit->value().isZero())) { price = priceEdit->value().abs(); - if (priceMode() == InvestTransactionEditor::PricePerTransaction) { + if (priceMode() == eDialogs::PriceMode::PricePerTransaction) { price = -price; s0.setValue(price.reduce()); if (!s0.shares().isZero()) s0.setPrice((price / s0.shares()).reduce()); } else { s0.setValue((shares * price).reduce()); s0.setPrice(price); } } if (!createCategorySplits(t, dynamic_cast(haveWidget("fee-account")), dynamic_cast(haveWidget("fee-amount")), MyMoneyMoney::ONE, feeSplits, m_feeSplits)) return false; if (!createCategorySplits(t, dynamic_cast(haveWidget("interest-account")), dynamic_cast(haveWidget("interest-amount")), MyMoneyMoney::MINUS_ONE, interestSplits, m_interestSplits)) return false; createAssetAccountSplit(assetAccountSplit, s0); MyMoneyMoney total = sumSplits(s0, feeSplits, interestSplits); assetAccountSplit.setValue(-total); - if (!m_parent->setupPrice(t, assetAccountSplit)) + if (!d->m_parent->setupPrice(t, assetAccountSplit)) return false; return true; } +Div::Div(InvestTransactionEditor* editor) : + Activity(editor) +{ +} + +Div::~Div() +{ +} + +eMyMoney::Split::InvestmentTransactionType Div::type() const +{ + return eMyMoney::Split::InvestmentTransactionType::Dividend; +} + void Div::showWidgets() const { static const QStringList visibleWidgetIds = QStringList() << "asset-account" << "interest-amount" << "total" << "interest-account" << "fee-account"; setWidgetVisibility(visibleWidgetIds, true); static const QStringList hiddenWidgetIds = QStringList() << "shares" << "price"; setWidgetVisibility(hiddenWidgetIds, false); setLabelText("interest-amount-label", i18n("Interest")); setLabelText("interest-label", i18n("Interest")); setLabelText("fee-label", i18n("Fees")); setLabelText("asset-label", i18n("Account")); setLabelText("total-label", i18nc("Total value", "Total")); } bool Div::isComplete(QString& reason) const { Q_UNUSED(reason) - bool rc = Activity::isComplete(reason); + auto rc = Activity::isComplete(reason); rc &= haveAssetAccount(); rc &= haveCategoryAndAmount("interest-account", QString(), false); rc &= haveInterest(false); return rc; } bool Div::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) { + Q_D(Activity); Q_UNUSED(m_feeSplits); Q_UNUSED(security); Q_UNUSED(currency); QString reason; if (!isComplete(reason)) return false; s0.setAction(eMyMoney::Split::InvestmentTransactionType::Dividend); // for dividends, we only use the stock split as a marker MyMoneyMoney shares; s0.setShares(shares); s0.setValue(shares); s0.setPrice(MyMoneyMoney::ONE); if (!createCategorySplits(t, dynamic_cast(haveWidget("fee-account")), dynamic_cast(haveWidget("fee-amount")), MyMoneyMoney::ONE, feeSplits, m_feeSplits)) return false; if (!createCategorySplits(t, dynamic_cast(haveWidget("interest-account")), dynamic_cast(haveWidget("interest-amount")), MyMoneyMoney::MINUS_ONE, interestSplits, m_interestSplits)) return false; createAssetAccountSplit(assetAccountSplit, s0); MyMoneyMoney total = sumSplits(s0, feeSplits, interestSplits); assetAccountSplit.setValue(-total); - if (!m_parent->setupPrice(t, assetAccountSplit)) + if (!d->m_parent->setupPrice(t, assetAccountSplit)) return false; return true; } +Reinvest::Reinvest(InvestTransactionEditor* editor) : + Activity(editor) +{ +} + +Reinvest::~Reinvest() +{ +} + +eMyMoney::Split::InvestmentTransactionType Reinvest::type() const +{ + return eMyMoney::Split::InvestmentTransactionType::ReinvestDividend; +} + void Reinvest::showWidgets() const { + Q_D(const Activity); static const QStringList visibleWidgetIds = QStringList() << "price" << "interest-account"; setWidgetVisibility(visibleWidgetIds, true); - kMyMoneyEdit* shareEdit = dynamic_cast(haveWidget("shares")); + auto shareEdit = dynamic_cast(haveWidget("shares")); shareEdit->show(); - shareEdit->setPrecision(MyMoneyMoney::denomToPrec(m_parent->security().smallestAccountFraction())); + shareEdit->setPrecision(MyMoneyMoney::denomToPrec(d->m_parent->security().smallestAccountFraction())); kMyMoneyEdit* intAmount = dynamic_cast(haveWidget("interest-amount")); intAmount->hide(); setLabelText("interest-amount-label", QString()); intAmount->setValue(MyMoneyMoney()); setLabelText("interest-label", i18n("Interest")); setLabelText("shares-label", i18n("Shares")); if (dynamic_cast(haveWidget("price-label"))) setLabelText("price-label", priceLabel()); setLabelText("total-label", i18nc("Total value", "Total")); } bool Reinvest::isComplete(QString& reason) const { - bool rc = Activity::isComplete(reason); + auto rc = Activity::isComplete(reason); rc &= haveCategoryAndAmount("interest-account", QString(), false); rc &= haveShares(); rc &= havePrice(); return rc; } bool Reinvest::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) { + Q_D(Activity); Q_UNUSED(assetAccountSplit); Q_UNUSED(security); Q_UNUSED(currency); Q_UNUSED(m_feeSplits) QString reason; if (!isComplete(reason)) return false; - kMyMoneyEdit* sharesEdit = dynamic_cast(haveWidget("shares")); - kMyMoneyEdit* priceEdit = dynamic_cast(haveWidget("price")); + auto sharesEdit = dynamic_cast(haveWidget("shares")); + auto priceEdit = dynamic_cast(haveWidget("price")); s0.setAction(eMyMoney::Split::InvestmentTransactionType::ReinvestDividend); MyMoneyMoney shares = s0.shares(); MyMoneyMoney price; if (!s0.shares().isZero()) price = (s0.value() / s0.shares()).reduce(); if (!isMultiSelection() || (isMultiSelection() && !sharesEdit->value().isZero())) { shares = sharesEdit->value().abs(); s0.setShares(shares); s0.setValue((shares * price).reduce()); s0.setPrice(price); } if (!isMultiSelection() || (isMultiSelection() && !priceEdit->value().isZero())) { price = priceEdit->value().abs(); - if (priceMode() == InvestTransactionEditor::PricePerTransaction) { + if (priceMode() == eDialogs::PriceMode::PricePerTransaction) { s0.setValue(price.reduce()); if (!s0.shares().isZero()) s0.setPrice((price / s0.shares()).reduce()); } else { s0.setValue((shares * price).reduce()); s0.setPrice(price); } } if (!createCategorySplits(t, dynamic_cast(haveWidget("interest-account")), dynamic_cast(haveWidget("interest-amount")), MyMoneyMoney::MINUS_ONE, interestSplits, m_interestSplits)) return false; if (interestSplits.count() != 1) { qDebug("more or less than one interest split in Reinvest::createTransaction. Not created."); return false; } MyMoneySplit& s1 = interestSplits[0]; MyMoneyMoney total = sumSplits(s0, feeSplits, QList()); s1.setValue(-total); - if (!m_parent->setupPrice(t, s1)) + if (!d->m_parent->setupPrice(t, s1)) return false; return true; } +Add::Add(InvestTransactionEditor* editor) : + Activity(editor) +{ +} + +Add::~Add() +{ +} + +eMyMoney::Split::InvestmentTransactionType Add::type() const +{ + return eMyMoney::Split::InvestmentTransactionType::AddShares; +} + void Add::showWidgets() const { - kMyMoneyEdit* shareEdit = dynamic_cast(haveWidget("shares")); + Q_D(const Activity); + auto shareEdit = dynamic_cast(haveWidget("shares")); shareEdit->show(); - shareEdit->setPrecision(MyMoneyMoney::denomToPrec(m_parent->security().smallestAccountFraction())); + shareEdit->setPrecision(MyMoneyMoney::denomToPrec(d->m_parent->security().smallestAccountFraction())); setLabelText("shares-label", i18n("Shares")); } bool Add::isComplete(QString& reason) const { - bool rc = Activity::isComplete(reason); + auto rc = Activity::isComplete(reason); rc &= haveShares(); return rc; } bool Add::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) { Q_UNUSED(t); Q_UNUSED(assetAccountSplit); Q_UNUSED(m_feeSplits); Q_UNUSED(m_interestSplits); Q_UNUSED(security); Q_UNUSED(currency); QString reason; if (!isComplete(reason)) return false; - kMyMoneyEdit* sharesEdit = dynamic_cast(haveWidget("shares")); + auto sharesEdit = dynamic_cast(haveWidget("shares")); s0.setAction(eMyMoney::Split::InvestmentTransactionType::AddShares); s0.setShares(sharesEdit->value().abs()); s0.setValue(MyMoneyMoney()); s0.setPrice(MyMoneyMoney()); assetAccountSplit.setValue(MyMoneyMoney());// Clear any leftover value from previous Dividend. feeSplits.clear(); interestSplits.clear(); return true; } +Remove::Remove(InvestTransactionEditor* editor) : + Activity(editor) +{ +} + +Remove::~Remove() +{ +} + +eMyMoney::Split::InvestmentTransactionType Remove::type() const +{ + return eMyMoney::Split::InvestmentTransactionType::RemoveShares; +} + void Remove::showWidgets() const { - kMyMoneyEdit* shareEdit = dynamic_cast(haveWidget("shares")); + Q_D(const Activity); + auto shareEdit = dynamic_cast(haveWidget("shares")); shareEdit->show(); - shareEdit->setPrecision(MyMoneyMoney::denomToPrec(m_parent->security().smallestAccountFraction())); + shareEdit->setPrecision(MyMoneyMoney::denomToPrec(d->m_parent->security().smallestAccountFraction())); setLabelText("shares-label", i18n("Shares")); } bool Remove::isComplete(QString& reason) const { - bool rc = Activity::isComplete(reason); + auto rc = Activity::isComplete(reason); rc &= haveShares(); return rc; } bool Remove::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) { Q_UNUSED(t); Q_UNUSED(assetAccountSplit); Q_UNUSED(m_feeSplits); Q_UNUSED(m_interestSplits); Q_UNUSED(security); Q_UNUSED(currency); QString reason; if (!isComplete(reason)) return false; - kMyMoneyEdit* sharesEdit = dynamic_cast(haveWidget("shares")); + auto sharesEdit = dynamic_cast(haveWidget("shares")); s0.setAction(eMyMoney::Split::InvestmentTransactionType::AddShares); s0.setShares(-(sharesEdit->value().abs())); s0.setValue(MyMoneyMoney()); s0.setPrice(MyMoneyMoney()); assetAccountSplit.setValue(MyMoneyMoney());// Clear any leftover value from previous Dividend. feeSplits.clear(); interestSplits.clear(); return true; } -void Split::showWidgets() const +Invest::Split::Split(InvestTransactionEditor* editor) : + Activity(editor) +{ +} + +Invest::Split::~Split() +{ +} + +eMyMoney::Split::InvestmentTransactionType Invest::Split::type() const +{ + return eMyMoney::Split::InvestmentTransactionType::SplitShares; +} + +void Invest::Split::showWidgets() const { // TODO do we need a special split ratio widget? // TODO maybe yes, currently the precision is the one of the fraction and might differ from it - kMyMoneyEdit* shareEdit = dynamic_cast(haveWidget("shares")); + auto shareEdit = dynamic_cast(haveWidget("shares")); shareEdit->show(); shareEdit->setPrecision(-1); setLabelText("shares-label", i18n("Ratio 1/")); } -bool Split::isComplete(QString& reason) const +bool Invest::Split::isComplete(QString& reason) const { - bool rc = Activity::isComplete(reason); + auto rc = Activity::isComplete(reason); rc &= haveShares(); return rc; } -bool Split::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) +bool Invest::Split::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) { Q_UNUSED(t); Q_UNUSED(assetAccountSplit); Q_UNUSED(m_feeSplits); Q_UNUSED(m_interestSplits); Q_UNUSED(security); Q_UNUSED(currency); - kMyMoneyEdit* sharesEdit = dynamic_cast(haveWidget("shares")); + auto sharesEdit = dynamic_cast(haveWidget("shares")); KMyMoneyCategory* cat; cat = dynamic_cast(haveWidget("interest-account")); cat->parentWidget()->hide(); cat = dynamic_cast(haveWidget("fee-account")); cat->parentWidget()->hide(); s0.setAction(eMyMoney::Split::InvestmentTransactionType::SplitShares); s0.setShares(sharesEdit->value().abs()); s0.setValue(MyMoneyMoney()); s0.setPrice(MyMoneyMoney()); feeSplits.clear(); interestSplits.clear(); return true; } +IntInc::IntInc(InvestTransactionEditor* editor) : + Activity(editor) +{ +} + +IntInc::~IntInc() +{ +} + +eMyMoney::Split::InvestmentTransactionType IntInc::type() const +{ + return eMyMoney::Split::InvestmentTransactionType::InterestIncome; +} + void IntInc::showWidgets() const { static const QStringList visibleWidgetIds = QStringList() << "asset-account" << "interest-amount" << "total" << "interest-account" << "fee-account"; setWidgetVisibility(visibleWidgetIds, true); static const QStringList hiddenWidgetIds = QStringList() << "shares" << "price" << "fee-amount"; setWidgetVisibility(hiddenWidgetIds, false); setLabelText("interest-amount-label", i18n("Interest")); setLabelText("interest-label", i18n("Interest")); setLabelText("fee-label", i18n("Fees")); setLabelText("asset-label", i18n("Account")); setLabelText("total-label", i18nc("Total value", "Total")); } bool IntInc::isComplete(QString& reason) const { Q_UNUSED(reason) - bool rc = Activity::isComplete(reason); + auto rc = Activity::isComplete(reason); rc &= haveAssetAccount(); rc &= haveCategoryAndAmount("interest-account", QString(), false); rc &= haveInterest(false); return rc; } bool IntInc::createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) { + Q_D(Activity); Q_UNUSED(security); Q_UNUSED(currency); QString reason; if (!isComplete(reason)) return false; s0.setAction(eMyMoney::Split::InvestmentTransactionType::InterestIncome); // for dividends, we only use the stock split as a marker MyMoneyMoney shares; s0.setShares(shares); s0.setValue(shares); s0.setPrice(MyMoneyMoney::ONE); if (!createCategorySplits(t, dynamic_cast(haveWidget("fee-account")), dynamic_cast(haveWidget("fee-amount")), MyMoneyMoney::ONE, feeSplits, m_feeSplits)) return false; if (!createCategorySplits(t, dynamic_cast(haveWidget("interest-account")), dynamic_cast(haveWidget("interest-amount")), MyMoneyMoney::MINUS_ONE, interestSplits, m_interestSplits)) return false; createAssetAccountSplit(assetAccountSplit, s0); MyMoneyMoney total = sumSplits(s0, feeSplits, interestSplits); assetAccountSplit.setValue(-total); - if (!m_parent->setupPrice(t, assetAccountSplit)) + if (!d->m_parent->setupPrice(t, assetAccountSplit)) return false; return true; } diff --git a/kmymoney/dialogs/investactivities.h b/kmymoney/dialogs/investactivities.h index 07c312727..195cd38f2 100644 --- a/kmymoney/dialogs/investactivities.h +++ b/kmymoney/dialogs/investactivities.h @@ -1,205 +1,195 @@ /*************************************************************************** investactivities.h ---------- begin : Fri Dec 15 2006 copyright : (C) 2006 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef INVESTACTIVITIES_H #define INVESTACTIVITIES_H // ---------------------------------------------------------------------------- // QT Includes -#include +#include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "investtransactioneditor.h" +class QWidget; +class QStringList; class kMyMoneyEdit; +class KMyMoneyCategory; + +class MyMoneyMoney; +class MyMoneySplit; +class MyMoneyTransaction; +class MyMoneySecurity; + +class InvestTransactionEditor; + +namespace eMyMoney { namespace Split { enum class InvestmentTransactionType; } } +namespace eDialogs { enum class PriceMode; } + +template class QList; +template class QMap; namespace Invest { +class ActivityPrivate; class Activity { + Q_DISABLE_COPY(Activity) + public: virtual eMyMoney::Split::InvestmentTransactionType type() const = 0; virtual void showWidgets() const = 0; virtual bool isComplete(QString& reason) const = 0; /** * Create a transaction @p t based on the split @p s0 and the data contained * in the widgets. In multiselection mode, @p assetAccountSplit, @p feeSplits, @p * interestSplits, @p security and @p currency are taken from the original * transaction and should be used as well. * * @return @p true if creation was successful, @p false otherwise */ virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) = 0; virtual void preloadAssetAccount(); - virtual ~Activity() {} - bool m_memoChanged; - QString m_memoText; + virtual ~Activity(); + + bool &memoChanged(); + QString& memoText(); protected: - Activity(InvestTransactionEditor* editor) : m_memoChanged(false) { - m_parent = editor; - } - QWidget* haveWidget(const QString& name) const { - return m_parent->haveWidget(name); - } + explicit Activity(InvestTransactionEditor* editor); + QWidget* haveWidget(const QString& name) const; bool haveAssetAccount() const; - bool haveFees(bool optional = false) const { - return haveCategoryAndAmount("fee-account", "fee-amount", optional); - } - bool haveInterest(bool optional = false) const { - return haveCategoryAndAmount("interest-account", "interest-amount", optional); - } + bool haveFees(bool optional = false) const; + bool haveInterest(bool optional = false) const; bool haveShares() const; bool havePrice() const; - bool isMultiSelection() const { - return m_parent->isMultiSelection(); - } + bool isMultiSelection() const; QString priceLabel() const; bool createCategorySplits(const MyMoneyTransaction& t, KMyMoneyCategory* cat, kMyMoneyEdit* amount, MyMoneyMoney factor, QList&splits, const QList& osplits) const; void createAssetAccountSplit(MyMoneySplit& split, const MyMoneySplit& stockSplit) const; MyMoneyMoney sumSplits(const MyMoneySplit& s0, const QList& feeSplits, const QList& interestSplits) const; bool haveCategoryAndAmount(const QString& category, const QString& amount, bool optional) const; void setLabelText(const QString& idx, const QString& txt) const; void setWidgetVisibility(const QStringList& widgetIds, bool visible) const; - InvestTransactionEditor::priceModeE priceMode() const { - return m_parent->priceMode(); - } + eDialogs::PriceMode priceMode() const; protected: - InvestTransactionEditor* m_parent; - QMap m_priceInfo; + ActivityPrivate* d_ptr; + Q_DECLARE_PRIVATE(Activity) }; class Buy : public Activity { public: - Buy(InvestTransactionEditor* editor) : Activity(editor) {} - virtual ~Buy() {} - virtual eMyMoney::Split::InvestmentTransactionType type() const { - return eMyMoney::Split::InvestmentTransactionType::BuyShares; - } - virtual void showWidgets() const; - virtual bool isComplete(QString& reason) const; - virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency); + explicit Buy(InvestTransactionEditor* editor); + ~Buy() override; + eMyMoney::Split::InvestmentTransactionType type() const override; + void showWidgets() const override; + bool isComplete(QString& reason) const override; + bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) override; }; class Sell : public Activity { public: - Sell(InvestTransactionEditor* editor) : Activity(editor) {} - virtual ~Sell() {} - virtual eMyMoney::Split::InvestmentTransactionType type() const { - return eMyMoney::Split::InvestmentTransactionType::SellShares; - } - virtual void showWidgets() const; - virtual bool isComplete(QString& reason) const; - virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency); + explicit Sell(InvestTransactionEditor* editor); + ~Sell() override; + eMyMoney::Split::InvestmentTransactionType type() const override; + void showWidgets() const override; + bool isComplete(QString& reason) const override; + bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) override; }; class Div : public Activity { public: - Div(InvestTransactionEditor* editor) : Activity(editor) {} - virtual ~Div() {} - virtual eMyMoney::Split::InvestmentTransactionType type() const { - return eMyMoney::Split::InvestmentTransactionType::Dividend; - } - virtual void showWidgets() const; - virtual bool isComplete(QString& reason) const; - virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency); + explicit Div(InvestTransactionEditor* editor); + ~Div() override; + eMyMoney::Split::InvestmentTransactionType type() const override; + void showWidgets() const override; + bool isComplete(QString& reason) const override; + bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) override; }; class Reinvest : public Activity { public: - Reinvest(InvestTransactionEditor* editor) : Activity(editor) {} - virtual ~Reinvest() {} - virtual eMyMoney::Split::InvestmentTransactionType type() const { - return eMyMoney::Split::InvestmentTransactionType::ReinvestDividend; - } - virtual void showWidgets() const; - virtual bool isComplete(QString& reason) const; - virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency); + explicit Reinvest(InvestTransactionEditor* editor); + ~Reinvest() override; + eMyMoney::Split::InvestmentTransactionType type() const override; + void showWidgets() const override; + bool isComplete(QString& reason) const override; + bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) override; }; class Add : public Activity { public: - Add(InvestTransactionEditor* editor) : Activity(editor) {} - virtual ~Add() {} - virtual eMyMoney::Split::InvestmentTransactionType type() const { - return eMyMoney::Split::InvestmentTransactionType::AddShares; - } - virtual void showWidgets() const; - virtual bool isComplete(QString& reason) const; - virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency); + explicit Add(InvestTransactionEditor* editor); + ~Add() override; + eMyMoney::Split::InvestmentTransactionType type() const override; + void showWidgets() const override; + bool isComplete(QString& reason) const override; + bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) override; }; class Remove : public Activity { public: - Remove(InvestTransactionEditor* editor) : Activity(editor) {} - virtual ~Remove() {} - virtual eMyMoney::Split::InvestmentTransactionType type() const { - return eMyMoney::Split::InvestmentTransactionType::RemoveShares; - } - virtual void showWidgets() const; - virtual bool isComplete(QString& reason) const; - virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency); + explicit Remove(InvestTransactionEditor* editor); + ~Remove() override; + eMyMoney::Split::InvestmentTransactionType type() const override; + void showWidgets() const override; + bool isComplete(QString& reason) const override; + bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) override; }; class Split : public Activity { public: - Split(InvestTransactionEditor* editor) : Activity(editor) {} - virtual ~Split() {} - virtual eMyMoney::Split::InvestmentTransactionType type() const { - return eMyMoney::Split::InvestmentTransactionType::SplitShares; - } - virtual void showWidgets() const; - virtual bool isComplete(QString& reason) const; - virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency); + explicit Split(InvestTransactionEditor* editor); + ~Split() override; + eMyMoney::Split::InvestmentTransactionType type() const override; + void showWidgets() const override; + bool isComplete(QString& reason) const override; + bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) override; }; class IntInc : public Activity { public: - IntInc(InvestTransactionEditor* editor) : Activity(editor) {} - virtual ~IntInc() {} - virtual eMyMoney::Split::InvestmentTransactionType type() const { - return eMyMoney::Split::InvestmentTransactionType::InterestIncome; - } - virtual void showWidgets() const; - virtual bool isComplete(QString& reason) const; - virtual bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency); + explicit IntInc(InvestTransactionEditor* editor); + ~IntInc() override; + eMyMoney::Split::InvestmentTransactionType type() const override; + void showWidgets() const override; + bool isComplete(QString& reason) const override; + bool createTransaction(MyMoneyTransaction& t, MyMoneySplit& s0, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& m_feeSplits, QList& interestSplits, QList& m_interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency) override; }; } // namespace Invest - - #endif // INVESTACTIVITIES_H diff --git a/kmymoney/dialogs/investtransactioneditor.cpp b/kmymoney/dialogs/investtransactioneditor.cpp index 401484ed3..0087e336d 100644 --- a/kmymoney/dialogs/investtransactioneditor.cpp +++ b/kmymoney/dialogs/investtransactioneditor.cpp @@ -1,1127 +1,1219 @@ /*************************************************************************** investtransactioneditor.cpp ---------- begin : Fri Dec 15 2006 copyright : (C) 2006 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "investtransactioneditor.h" +#include "transactioneditor_p.h" #include // ---------------------------------------------------------------------------- // QT Includes #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include // ---------------------------------------------------------------------------- // Project Includes #include "kmymoneycategory.h" #include "kmymoneydateinput.h" #include "kmymoneyedit.h" #include "kmymoneyaccountselector.h" #include "kmymoneymvccombo.h" #include "mymoneyfile.h" #include "mymoneyprice.h" #include "ksplittransactiondlg.h" #include "kcurrencycalculator.h" #include "kmymoneyglobalsettings.h" #include "investactivities.h" -#include "kmymoneyutils.h" #include "kmymoneycompletion.h" +#include "dialogenums.h" +using namespace eMyMoney; using namespace KMyMoneyRegister; using namespace KMyMoneyTransactionForm; using namespace Invest; -class InvestTransactionEditor::Private +class InvestTransactionEditorPrivate : public TransactionEditorPrivate { + Q_DISABLE_COPY(InvestTransactionEditorPrivate) + Q_DECLARE_PUBLIC(InvestTransactionEditor) friend class Invest::Activity; public: - Private(InvestTransactionEditor* parent) : - m_parent(parent), - m_activity(0) { + InvestTransactionEditorPrivate(InvestTransactionEditor* qq) : + TransactionEditorPrivate(qq), + m_activity(0) + { m_phonyAccount = MyMoneyAccount("Phony-ID", MyMoneyAccount()); } - ~Private() { + ~InvestTransactionEditorPrivate() + { delete m_activity; } - QWidget* haveWidget(const QString& name) { - return m_parent->haveWidget(name); + QWidget* haveWidget(const QString& name) + { + Q_Q(InvestTransactionEditor); + return q->haveWidget(name); } - void hideCategory(const QString& name) { + void hideCategory(const QString& name) + { if (KMyMoneyCategory* cat = dynamic_cast(haveWidget(name))) { cat->hide(); cat->splitButton()->hide(); } } - InvestTransactionEditor* m_parent; - Activity* m_activity; - MyMoneyAccount m_phonyAccount; - MyMoneySplit m_phonySplit; + void activityFactory(eMyMoney::Split::InvestmentTransactionType type) + { + Q_Q(InvestTransactionEditor); + if (!m_activity || type != m_activity->type()) { + delete m_activity; + switch (type) { + default: + case eMyMoney::Split::InvestmentTransactionType::BuyShares: + m_activity = new Buy(q); + break; + case eMyMoney::Split::InvestmentTransactionType::SellShares: + m_activity = new Sell(q); + break; + case eMyMoney::Split::InvestmentTransactionType::Dividend: + case eMyMoney::Split::InvestmentTransactionType::Yield: + m_activity = new Div(q); + break; + case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend: + m_activity = new Reinvest(q); + break; + case eMyMoney::Split::InvestmentTransactionType::AddShares: + m_activity = new Add(q); + break; + case eMyMoney::Split::InvestmentTransactionType::RemoveShares: + m_activity = new Remove(q); + break; + case eMyMoney::Split::InvestmentTransactionType::SplitShares: + m_activity = new Invest::Split(q); + break; + case eMyMoney::Split::InvestmentTransactionType::InterestIncome: + m_activity = new IntInc(q); + break; + } + } + } + + MyMoneyMoney subtotal(const QList& splits) const + { + QList::const_iterator it_s; + MyMoneyMoney sum; + + for (it_s = splits.begin(); it_s != splits.end(); ++it_s) { + sum += (*it_s).value(); + } + + return sum; + } + + /** + * This method creates a transaction to be used for the split fee/interest editor. + * It has a reference to a phony account and the splits contained in @a splits . + */ + bool createPseudoTransaction(MyMoneyTransaction& t, const QList& splits) + { + t.removeSplits(); + + MyMoneySplit split; + split.setAccountId(m_phonyAccount.id()); + split.setValue(-subtotal(splits)); + split.setShares(split.value()); + t.addSplit(split); + m_phonySplit = split; + + QList::const_iterator it_s; + for (it_s = splits.begin(); it_s != splits.end(); ++it_s) { + split = *it_s; + split.clearId(); + t.addSplit(split); + } + return true; + } + + /** + * Convenience method used by slotEditInterestSplits() and slotEditFeeSplits(). + * + * @param categoryWidgetName name of the category widget + * @param amountWidgetName name of the amount widget + * @param splits the splits that make up the transaction to be edited + * @param isIncome @c false for fees, @c true for interest + * @param slotEditSplits name of the slot to be connected to the focusIn signal of the + * category widget named @p categoryWidgetName in case of multiple splits + * in @p splits . + */ + + int editSplits(const QString& categoryWidgetName, + const QString& amountWidgetName, + QList& splits, + bool isIncome, + const char* slotEditSplits) + { + Q_Q(InvestTransactionEditor); + int rc = QDialog::Rejected; + + if (!m_openEditSplits) { + // only get in here in a single instance + m_openEditSplits = true; + + // force focus change to update all data + KMyMoneyCategory* category = dynamic_cast(m_editWidgets[categoryWidgetName]); + QWidget* w = category->splitButton(); + if (w) + w->setFocus(); + + kMyMoneyEdit* amount = dynamic_cast(haveWidget(amountWidgetName)); + + MyMoneyTransaction transaction; + transaction.setCommodity(m_currency.id()); + if (splits.count() == 0 && !category->selectedItem().isEmpty()) { + MyMoneySplit s; + s.setAccountId(category->selectedItem()); + s.setShares(amount->value()); + s.setValue(s.shares()); + splits << s; + } + // use the transactions commodity as the currency indicator for the splits + // this is used to allow some useful setting for the fractions in the amount fields + try { + m_phonyAccount.setCurrencyId(m_transaction.commodity()); + m_phonyAccount.fraction(MyMoneyFile::instance()->security(m_transaction.commodity())); + } catch (const MyMoneyException &) { + qDebug("Unable to setup precision"); + } + + if (createPseudoTransaction(transaction, splits)) { + MyMoneyMoney value; + + QPointer dlg = new KSplitTransactionDlg(transaction, + m_phonySplit, + m_phonyAccount, + false, + isIncome, + MyMoneyMoney(), + m_priceInfo, + m_regForm); + // q->connect(dlg, SIGNAL(newCategory(MyMoneyAccount&)), q, SIGNAL(newCategory(MyMoneyAccount&))); + + if ((rc = dlg->exec()) == QDialog::Accepted) { + transaction = dlg->transaction(); + // collect splits out of the transaction + splits.clear(); + QList::const_iterator it_s; + MyMoneyMoney fees; + for (it_s = transaction.splits().constBegin(); it_s != transaction.splits().constEnd(); ++it_s) { + if ((*it_s).accountId() == m_phonyAccount.id()) + continue; + splits << *it_s; + fees += (*it_s).shares(); + } + if (isIncome) + fees = -fees; + + QString categoryId; + q->setupCategoryWidget(category, splits, categoryId, slotEditSplits); + amount->setValue(fees); + q->slotUpdateTotalAmount(); + } + + delete dlg; + } + + // focus jumps into the memo field + if ((w = haveWidget("memo")) != 0) { + w->setFocus(); + } + + m_openEditSplits = false; + } + return rc; + } + + void updatePriceMode(const MyMoneySplit& split = MyMoneySplit()) + { + Q_Q(InvestTransactionEditor); + auto label = dynamic_cast(haveWidget("price-label")); + if (label) { + auto sharesEdit = dynamic_cast(haveWidget("shares")); + auto priceEdit = dynamic_cast(haveWidget("price")); + MyMoneyMoney price; + if (!split.id().isEmpty()) + price = split.price().reduce(); + else + price = priceEdit->value().abs(); + + if (q->priceMode() == eDialogs::PriceMode::PricePerTransaction) { + priceEdit->setPrecision(m_currency.pricePrecision()); + label->setText(i18n("Transaction amount")); + if (!sharesEdit->value().isZero()) + priceEdit->setValue(sharesEdit->value().abs() * price); + + } else if (q->priceMode() == eDialogs::PriceMode::PricePerShare) { + priceEdit->setPrecision(m_security.pricePrecision()); + label->setText(i18n("Price/Share")); + priceEdit->setValue(price); + } else + priceEdit->setValue(price); + } + } + +// InvestTransactionEditor* q_ptr; + Activity* m_activity; + MyMoneyAccount m_phonyAccount; + MyMoneySplit m_phonySplit; + MyMoneySplit m_assetAccountSplit; + QList m_interestSplits; + QList m_feeSplits; + MyMoneySecurity m_security; + MyMoneySecurity m_currency; + eMyMoney::Split::InvestmentTransactionType m_transactionType; }; InvestTransactionEditor::InvestTransactionEditor() : - m_transactionType(eMyMoney::Split::InvestmentTransactionType::UnknownTransactionType), - d(new Private(this)) + TransactionEditor(*new InvestTransactionEditorPrivate(this)) { + Q_D(InvestTransactionEditor); + d->m_transactionType = eMyMoney::Split::InvestmentTransactionType::UnknownTransactionType; } InvestTransactionEditor::~InvestTransactionEditor() { - delete d; } -InvestTransactionEditor::InvestTransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::InvestTransaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate) : - TransactionEditor(regForm, item, list, lastPostDate), - d(new Private(this)) +InvestTransactionEditor::InvestTransactionEditor(TransactionEditorContainer* regForm, + KMyMoneyRegister::InvestTransaction* item, + const KMyMoneyRegister::SelectedTransactions& list, + const QDate& lastPostDate) : + TransactionEditor(*new InvestTransactionEditorPrivate(this), + regForm, + item, + list, + lastPostDate) { + Q_D(InvestTransactionEditor); // after the gometries of the container are updated hide the widgets which are not needed by the current activity - connect(m_regForm, SIGNAL(geometriesUpdated()), this, SLOT(slotTransactionContainerGeometriesUpdated())); + connect(d->m_regForm, &TransactionEditorContainer::geometriesUpdated, this, &InvestTransactionEditor::slotTransactionContainerGeometriesUpdated); // dissect the transaction into its type, splits, currency, security etc. - KMyMoneyUtils::dissectTransaction(m_transaction, m_split, - m_assetAccountSplit, - m_feeSplits, - m_interestSplits, - m_security, - m_currency, - m_transactionType); + KMyMoneyUtils::dissectTransaction(d->m_transaction, d->m_split, + d->m_assetAccountSplit, + d->m_feeSplits, + d->m_interestSplits, + d->m_security, + d->m_currency, + d->m_transactionType); // determine initial activity object - activityFactory(m_transactionType); -} - -void InvestTransactionEditor::activityFactory(eMyMoney::Split::InvestmentTransactionType type) -{ - if (!d->m_activity || type != d->m_activity->type()) { - delete d->m_activity; - switch (type) { - default: - case eMyMoney::Split::InvestmentTransactionType::BuyShares: - d->m_activity = new Buy(this); - break; - case eMyMoney::Split::InvestmentTransactionType::SellShares: - d->m_activity = new Sell(this); - break; - case eMyMoney::Split::InvestmentTransactionType::Dividend: - case eMyMoney::Split::InvestmentTransactionType::Yield: - d->m_activity = new Div(this); - break; - case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend: - d->m_activity = new Reinvest(this); - break; - case eMyMoney::Split::InvestmentTransactionType::AddShares: - d->m_activity = new Add(this); - break; - case eMyMoney::Split::InvestmentTransactionType::RemoveShares: - d->m_activity = new Remove(this); - break; - case eMyMoney::Split::InvestmentTransactionType::SplitShares: - d->m_activity = new Split(this); - break; - case eMyMoney::Split::InvestmentTransactionType::InterestIncome: - d->m_activity = new IntInc(this); - break; - } - } + d->activityFactory(d->m_transactionType); } void InvestTransactionEditor::createEditWidgets() { - KMyMoneyActivityCombo* activity = new KMyMoneyActivityCombo(); - m_editWidgets["activity"] = activity; - connect(activity, SIGNAL(activitySelected(eMyMoney::Split::InvestmentTransactionType)), this, SLOT(slotUpdateActivity(eMyMoney::Split::InvestmentTransactionType))); - connect(activity, SIGNAL(activitySelected(eMyMoney::Split::InvestmentTransactionType)), this, SLOT(slotUpdateButtonState())); + Q_D(InvestTransactionEditor); + auto activity = new KMyMoneyActivityCombo(); + d->m_editWidgets["activity"] = activity; + connect(activity, &KMyMoneyActivityCombo::activitySelected, this, &InvestTransactionEditor::slotUpdateActivity); + connect(activity, &KMyMoneyActivityCombo::activitySelected, this, &InvestTransactionEditor::slotUpdateButtonState); - m_editWidgets["postdate"] = new kMyMoneyDateInput; + d->m_editWidgets["postdate"] = new kMyMoneyDateInput; - KMyMoneySecurity* security = new KMyMoneySecurity; + auto security = new KMyMoneySecurity; security->setPlaceholderText(i18n("Security")); - m_editWidgets["security"] = security; - connect(security, SIGNAL(itemSelected(QString)), this, SLOT(slotUpdateSecurity(QString))); - connect(security, SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(security, SIGNAL(createItem(QString,QString&)), this, SLOT(slotCreateSecurity(QString,QString&))); - connect(security, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); + d->m_editWidgets["security"] = security; + connect(security, &KMyMoneyCombo::itemSelected, this, &InvestTransactionEditor::slotUpdateSecurity); + connect(security, &QComboBox::editTextChanged, this, &InvestTransactionEditor::slotUpdateButtonState); + connect(security, &KMyMoneyCombo::createItem, this, &InvestTransactionEditor::slotCreateSecurity); + connect(security, &KMyMoneyCombo::objectCreation, this, &TransactionEditor::objectCreation); - KMyMoneyCategory* asset = new KMyMoneyCategory(0, false); + auto asset = new KMyMoneyCategory(0, false); asset->setPlaceholderText(i18n("Asset account")); - m_editWidgets["asset-account"] = asset; - connect(asset, SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(asset, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); + d->m_editWidgets["asset-account"] = asset; + connect(asset, &QComboBox::editTextChanged, this, &InvestTransactionEditor::slotUpdateButtonState); + connect(asset, &KMyMoneyCombo::objectCreation, this, &TransactionEditor::objectCreation); - KMyMoneyCategory* fees = new KMyMoneyCategory(0, true); + auto fees = new KMyMoneyCategory(0, true); fees->setPlaceholderText(i18n("Fees")); - m_editWidgets["fee-account"] = fees; - connect(fees, SIGNAL(itemSelected(QString)), this, SLOT(slotUpdateFeeCategory(QString))); - connect(fees, SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(fees, SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateFeeVisibility(QString))); - connect(fees, SIGNAL(createItem(QString,QString&)), this, SLOT(slotCreateFeeCategory(QString,QString&))); - connect(fees, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); - connect(fees->splitButton(), SIGNAL(clicked()), this, SLOT(slotEditFeeSplits())); - - KMyMoneyCategory* interest = new KMyMoneyCategory(0, true); + d->m_editWidgets["fee-account"] = fees; + connect(fees, &KMyMoneyCombo::itemSelected, this, &InvestTransactionEditor::slotUpdateFeeCategory); + connect(fees, &QComboBox::editTextChanged, this, &InvestTransactionEditor::slotUpdateButtonState); + connect(fees, &QComboBox::editTextChanged, this, &InvestTransactionEditor::slotUpdateFeeVisibility); + connect(fees, &KMyMoneyCombo::createItem, this, &InvestTransactionEditor::slotCreateFeeCategory); + connect(fees, &KMyMoneyCombo::objectCreation, this, &TransactionEditor::objectCreation); + connect(fees->splitButton(), &QAbstractButton::clicked, this, &InvestTransactionEditor::slotEditFeeSplits); + + auto interest = new KMyMoneyCategory(0, true); interest->setPlaceholderText(i18n("Interest")); - m_editWidgets["interest-account"] = interest; - connect(interest, SIGNAL(itemSelected(QString)), this, SLOT(slotUpdateInterestCategory(QString))); - connect(interest, SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(interest, SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateInterestVisibility(QString))); - connect(interest, SIGNAL(createItem(QString,QString&)), this, SLOT(slotCreateInterestCategory(QString,QString&))); - connect(interest, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); - connect(interest->splitButton(), SIGNAL(clicked()), this, SLOT(slotEditInterestSplits())); - - KTagContainer* tag = new KTagContainer; + d->m_editWidgets["interest-account"] = interest; + connect(interest, &KMyMoneyCombo::itemSelected, this, &InvestTransactionEditor::slotUpdateInterestCategory); + connect(interest, &QComboBox::editTextChanged, this, &InvestTransactionEditor::slotUpdateButtonState); + connect(interest, &QComboBox::editTextChanged, this, &InvestTransactionEditor::slotUpdateInterestVisibility); + connect(interest, &KMyMoneyCombo::createItem, this, &InvestTransactionEditor::slotCreateInterestCategory); + connect(interest, &KMyMoneyCombo::objectCreation, this, &TransactionEditor::objectCreation); + connect(interest->splitButton(), &QAbstractButton::clicked, this, &InvestTransactionEditor::slotEditInterestSplits); + + auto tag = new KTagContainer; tag->tagCombo()->setPlaceholderText(i18n("Tag")); tag->tagCombo()->setObjectName(QLatin1String("Tag")); - m_editWidgets["tag"] = tag; - connect(tag->tagCombo(), SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(tag->tagCombo(), SIGNAL(createItem(QString,QString&)), this, SIGNAL(createTag(QString,QString&))); - connect(tag->tagCombo(), SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); + d->m_editWidgets["tag"] = tag; + connect(tag->tagCombo(), &QComboBox::editTextChanged, this, &InvestTransactionEditor::slotUpdateButtonState); + connect(tag->tagCombo(), &KMyMoneyMVCCombo::createItem, this, &TransactionEditor::createTag); + connect(tag->tagCombo(), &KMyMoneyMVCCombo::objectCreation, this, &TransactionEditor::objectCreation); - KTextEdit* memo = new KTextEdit; + auto memo = new KTextEdit; memo->setTabChangesFocus(true); - m_editWidgets["memo"] = memo; - connect(memo, SIGNAL(textChanged()), this, SLOT(slotUpdateInvestMemoState())); - connect(memo, SIGNAL(textChanged()), this, SLOT(slotUpdateButtonState())); + d->m_editWidgets["memo"] = memo; + connect(memo, &QTextEdit::textChanged, this, &InvestTransactionEditor::slotUpdateInvestMemoState); + connect(memo, &QTextEdit::textChanged, this, &InvestTransactionEditor::slotUpdateButtonState); - d->m_activity->m_memoText.clear(); - d->m_activity->m_memoChanged = false; + d->m_activity->memoText().clear(); + d->m_activity->memoChanged() = false; kMyMoneyEdit* value = new kMyMoneyEdit; value->setPlaceholderText(i18n("Shares")); value->setResetButtonVisible(false); - m_editWidgets["shares"] = value; - connect(value, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(value, SIGNAL(valueChanged(QString)), this, SLOT(slotUpdateTotalAmount())); + d->m_editWidgets["shares"] = value; + connect(value, &kMyMoneyEdit::textChanged, this, &InvestTransactionEditor::slotUpdateButtonState); + connect(value, &kMyMoneyEdit::valueChanged, this, &InvestTransactionEditor::slotUpdateTotalAmount); value = new kMyMoneyEdit; value->setPlaceholderText(i18n("Price")); value->setResetButtonVisible(false); - m_editWidgets["price"] = value; - connect(value, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(value, SIGNAL(valueChanged(QString)), this, SLOT(slotUpdateTotalAmount())); + d->m_editWidgets["price"] = value; + connect(value, &kMyMoneyEdit::textChanged, this, &InvestTransactionEditor::slotUpdateButtonState); + connect(value, &kMyMoneyEdit::valueChanged, this, &InvestTransactionEditor::slotUpdateTotalAmount); value = new kMyMoneyEdit; // TODO once we have the selected transactions as array of Transaction // we can allow multiple splits for fee and interest value->setResetButtonVisible(false); - m_editWidgets["fee-amount"] = value; - connect(value, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(value, SIGNAL(valueChanged(QString)), this, SLOT(slotUpdateTotalAmount())); + d->m_editWidgets["fee-amount"] = value; + connect(value, &kMyMoneyEdit::textChanged, this, &InvestTransactionEditor::slotUpdateButtonState); + connect(value, &kMyMoneyEdit::valueChanged, this, &InvestTransactionEditor::slotUpdateTotalAmount); value = new kMyMoneyEdit; // TODO once we have the selected transactions as array of Transaction // we can allow multiple splits for fee and interest value->setResetButtonVisible(false); - m_editWidgets["interest-amount"] = value; - connect(value, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(value, SIGNAL(valueChanged(QString)), this, SLOT(slotUpdateTotalAmount())); + d->m_editWidgets["interest-amount"] = value; + connect(value, &kMyMoneyEdit::textChanged, this, &InvestTransactionEditor::slotUpdateButtonState); + connect(value, &kMyMoneyEdit::valueChanged, this, &InvestTransactionEditor::slotUpdateTotalAmount); - KMyMoneyReconcileCombo* reconcile = new KMyMoneyReconcileCombo; - m_editWidgets["status"] = reconcile; - connect(reconcile, SIGNAL(itemSelected(QString)), this, SLOT(slotUpdateButtonState())); + auto reconcile = new KMyMoneyReconcileCombo; + d->m_editWidgets["status"] = reconcile; + connect(reconcile, &KMyMoneyMVCCombo::itemSelected, this, &InvestTransactionEditor::slotUpdateButtonState); KMyMoneyRegister::QWidgetContainer::iterator it_w; - for (it_w = m_editWidgets.begin(); it_w != m_editWidgets.end(); ++it_w) { + for (it_w = d->m_editWidgets.begin(); it_w != d->m_editWidgets.end(); ++it_w) { (*it_w)->installEventFilter(this); } QLabel* label; - m_editWidgets["activity-label"] = label = new QLabel(i18n("Activity")); + d->m_editWidgets["activity-label"] = label = new QLabel(i18n("Activity")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["postdate-label"] = label = new QLabel(i18n("Date")); + d->m_editWidgets["postdate-label"] = label = new QLabel(i18n("Date")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["security-label"] = label = new QLabel(i18n("Security")); + d->m_editWidgets["security-label"] = label = new QLabel(i18n("Security")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["shares-label"] = label = new QLabel(i18n("Shares")); + d->m_editWidgets["shares-label"] = label = new QLabel(i18n("Shares")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["asset-label"] = label = new QLabel(i18n("Account")); + d->m_editWidgets["asset-label"] = label = new QLabel(i18n("Account")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["price-label"] = label = new QLabel(i18n("Price/share")); + d->m_editWidgets["price-label"] = label = new QLabel(i18n("Price/share")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["fee-label"] = label = new QLabel(i18n("Fees")); + d->m_editWidgets["fee-label"] = label = new QLabel(i18n("Fees")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["fee-amount-label"] = label = new QLabel(""); + d->m_editWidgets["fee-amount-label"] = label = new QLabel(""); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["interest-label"] = label = new QLabel(i18n("Interest")); + d->m_editWidgets["interest-label"] = label = new QLabel(i18n("Interest")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["interest-amount-label"] = label = new QLabel(i18n("Interest")); + d->m_editWidgets["interest-amount-label"] = label = new QLabel(i18n("Interest")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["memo-label"] = label = new QLabel(i18n("Memo")); + d->m_editWidgets["memo-label"] = label = new QLabel(i18n("Memo")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["total"] = label = new QLabel(""); + d->m_editWidgets["total"] = label = new QLabel(""); label->setAlignment(Qt::AlignVCenter | Qt::AlignRight); - m_editWidgets["total-label"] = label = new QLabel(i18nc("Total value", "Total")); + d->m_editWidgets["total-label"] = label = new QLabel(i18nc("Total value", "Total")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["status-label"] = label = new QLabel(i18n("Status")); + d->m_editWidgets["status-label"] = label = new QLabel(i18n("Status")); label->setAlignment(Qt::AlignVCenter); // if we don't have more than 1 selected transaction, we don't need // the "don't change" item in some of the combo widgets - if (m_transactions.count() < 2) { + if (d->m_transactions.count() < 2) { reconcile->removeDontCare(); } } int InvestTransactionEditor::slotEditFeeSplits() { - return editSplits("fee-account", "fee-amount", m_feeSplits, false, SLOT(slotEditFeeSplits())); + Q_D(InvestTransactionEditor); + return d->editSplits("fee-account", "fee-amount", d->m_feeSplits, false, SLOT(slotEditFeeSplits())); } int InvestTransactionEditor::slotEditInterestSplits() { - return editSplits("interest-account", "interest-amount", m_interestSplits, true, SLOT(slotEditInterestSplits())); -} - -int InvestTransactionEditor::editSplits(const QString& categoryWidgetName, const QString& amountWidgetName, QList& splits, bool isIncome, const char* slotEditSplits) -{ - int rc = QDialog::Rejected; - - if (!m_openEditSplits) { - // only get in here in a single instance - m_openEditSplits = true; - - // force focus change to update all data - KMyMoneyCategory* category = dynamic_cast(m_editWidgets[categoryWidgetName]); - QWidget* w = category->splitButton(); - if (w) - w->setFocus(); - - kMyMoneyEdit* amount = dynamic_cast(haveWidget(amountWidgetName)); - - MyMoneyTransaction transaction; - transaction.setCommodity(m_currency.id()); - if (splits.count() == 0 && !category->selectedItem().isEmpty()) { - MyMoneySplit s; - s.setAccountId(category->selectedItem()); - s.setShares(amount->value()); - s.setValue(s.shares()); - splits << s; - } - // use the transactions commodity as the currency indicator for the splits - // this is used to allow some useful setting for the fractions in the amount fields - try { - d->m_phonyAccount.setCurrencyId(m_transaction.commodity()); - d->m_phonyAccount.fraction(MyMoneyFile::instance()->security(m_transaction.commodity())); - } catch (const MyMoneyException &) { - qDebug("Unable to setup precision"); - } - - if (createPseudoTransaction(transaction, splits)) { - MyMoneyMoney value; - - QPointer dlg = new KSplitTransactionDlg(transaction, - d->m_phonySplit, - d->m_phonyAccount, - false, - isIncome, - MyMoneyMoney(), - m_priceInfo, - m_regForm); - // connect(dlg, SIGNAL(newCategory(MyMoneyAccount&)), this, SIGNAL(newCategory(MyMoneyAccount&))); - - if ((rc = dlg->exec()) == QDialog::Accepted) { - transaction = dlg->transaction(); - // collect splits out of the transaction - splits.clear(); - QList::const_iterator it_s; - MyMoneyMoney fees; - for (it_s = transaction.splits().constBegin(); it_s != transaction.splits().constEnd(); ++it_s) { - if ((*it_s).accountId() == d->m_phonyAccount.id()) - continue; - splits << *it_s; - fees += (*it_s).shares(); - } - if (isIncome) - fees = -fees; - - QString categoryId; - setupCategoryWidget(category, splits, categoryId, slotEditSplits); - amount->setValue(fees); - slotUpdateTotalAmount(); - } - - delete dlg; - } - - // focus jumps into the memo field - if ((w = haveWidget("memo")) != 0) { - w->setFocus(); - } - - m_openEditSplits = false; - } - return rc; -} - -bool InvestTransactionEditor::createPseudoTransaction(MyMoneyTransaction& t, const QList& splits) -{ - t.removeSplits(); - - MyMoneySplit split; - split.setAccountId(d->m_phonyAccount.id()); - split.setValue(-subtotal(splits)); - split.setShares(split.value()); - t.addSplit(split); - d->m_phonySplit = split; - - QList::const_iterator it_s; - for (it_s = splits.begin(); it_s != splits.end(); ++it_s) { - split = *it_s; - split.clearId(); - t.addSplit(split); - } - return true; + Q_D(InvestTransactionEditor); + return d->editSplits("interest-account", "interest-amount", d->m_interestSplits, true, SLOT(slotEditInterestSplits())); } void InvestTransactionEditor::slotCreateSecurity(const QString& name, QString& id) { + Q_D(InvestTransactionEditor); MyMoneyAccount acc; QRegExp exp("([^:]+)"); if (exp.indexIn(name) != -1) { acc.setName(exp.cap(1)); - emit createSecurity(acc, m_account); + emit createSecurity(acc, d->m_account); // return id id = acc.id(); if (!id.isEmpty()) { slotUpdateSecurity(id); } } } void InvestTransactionEditor::slotCreateFeeCategory(const QString& name, QString& id) { MyMoneyAccount acc; acc.setName(name); emit createCategory(acc, MyMoneyFile::instance()->expense()); // return id id = acc.id(); } void InvestTransactionEditor::slotUpdateFeeCategory(const QString& id) { haveWidget("fee-amount")->setDisabled(id.isEmpty()); } void InvestTransactionEditor::slotUpdateFeeVisibility(const QString& txt) { + Q_D(InvestTransactionEditor); static const QSet transactionTypesWithoutFee = QSet() << eMyMoney::Split::InvestmentTransactionType::AddShares << eMyMoney::Split::InvestmentTransactionType::RemoveShares << eMyMoney::Split::InvestmentTransactionType::SplitShares; kMyMoneyEdit* feeAmount = dynamic_cast(haveWidget("fee-amount")); feeAmount->setHidden(txt.isEmpty()); QLabel* l = dynamic_cast(haveWidget("fee-amount-label")); KMyMoneyCategory* fee = dynamic_cast(haveWidget("fee-account")); const bool hideFee = txt.isEmpty() || transactionTypesWithoutFee.contains(d->m_activity->type()); // no fee expected so hide if (hideFee) { if (l) { l->setText(""); } feeAmount->hide(); fee->splitButton()->hide(); } else { if (l) { l->setText(i18n("Fee Amount")); } feeAmount->show(); fee->splitButton()->show(); } } void InvestTransactionEditor::slotUpdateInterestCategory(const QString& id) { haveWidget("interest-amount")->setDisabled(id.isEmpty()); } void InvestTransactionEditor::slotUpdateInterestVisibility(const QString& txt) { + Q_D(InvestTransactionEditor); static const QSet transactionTypesWithInterest = QSet() << eMyMoney::Split::InvestmentTransactionType::BuyShares << eMyMoney::Split::InvestmentTransactionType::SellShares << eMyMoney::Split::InvestmentTransactionType::Dividend << eMyMoney::Split::InvestmentTransactionType::InterestIncome << eMyMoney::Split::InvestmentTransactionType::Yield; QWidget* w = haveWidget("interest-amount"); w->setHidden(txt.isEmpty()); QLabel* l = dynamic_cast(haveWidget("interest-amount-label")); KMyMoneyCategory* interest = dynamic_cast(haveWidget("interest-account")); const bool showInterest = !txt.isEmpty() && transactionTypesWithInterest.contains(d->m_activity->type()); if (interest && showInterest) { interest->splitButton()->show(); w->show(); if (l) l->setText(i18n("Interest")); } else { if (interest) { interest->splitButton()->hide(); w->hide(); if (l) l->setText(QString()); } } } void InvestTransactionEditor::slotCreateInterestCategory(const QString& name, QString& id) { MyMoneyAccount acc; acc.setName(name); emit createCategory(acc, MyMoneyFile::instance()->income()); id = acc.id(); } void InvestTransactionEditor::slotReloadEditWidgets() { - KMyMoneyCategory* interest = dynamic_cast(haveWidget("interest-account")); - KMyMoneyCategory* fees = dynamic_cast(haveWidget("fee-account")); - KMyMoneySecurity* security = dynamic_cast(haveWidget("security")); + Q_D(InvestTransactionEditor); + auto interest = dynamic_cast(haveWidget("interest-account")); + auto fees = dynamic_cast(haveWidget("fee-account")); + auto security = dynamic_cast(haveWidget("security")); AccountSet aSet; QString id; // interest-account aSet.clear(); - aSet.addAccountGroup(eMyMoney::Account::Income); + aSet.addAccountGroup(Account::Income); aSet.load(interest->selector()); - setupCategoryWidget(interest, m_interestSplits, id, SLOT(slotEditInterestSplits())); + setupCategoryWidget(interest, d->m_interestSplits, id, SLOT(slotEditInterestSplits())); // fee-account aSet.clear(); - aSet.addAccountGroup(eMyMoney::Account::Expense); + aSet.addAccountGroup(Account::Expense); aSet.load(fees->selector()); - setupCategoryWidget(fees, m_feeSplits, id, SLOT(slotEditFeeSplits())); + setupCategoryWidget(fees, d->m_feeSplits, id, SLOT(slotEditFeeSplits())); // security aSet.clear(); - aSet.load(security->selector(), i18n("Security"), m_account.accountList(), true); + aSet.load(security->selector(), i18n("Security"), d->m_account.accountList(), true); } -void InvestTransactionEditor::loadEditWidgets(KMyMoneyRegister::Action /* action */) +void InvestTransactionEditor::loadEditWidgets(KMyMoneyRegister::Action) { + loadEditWidgets(); +} + +void InvestTransactionEditor::loadEditWidgets() +{ + Q_D(InvestTransactionEditor); QString id; - kMyMoneyDateInput* postDate = dynamic_cast(haveWidget("postdate")); - KMyMoneyReconcileCombo* reconcile = dynamic_cast(haveWidget("status")); - KMyMoneySecurity* security = dynamic_cast(haveWidget("security")); - KMyMoneyActivityCombo* activity = dynamic_cast(haveWidget("activity")); - KMyMoneyCategory* asset = dynamic_cast(haveWidget("asset-account")); - KTextEdit* memo = dynamic_cast(m_editWidgets["memo"]); + auto postDate = dynamic_cast(haveWidget("postdate")); + auto reconcile = dynamic_cast(haveWidget("status")); + auto security = dynamic_cast(haveWidget("security")); + auto activity = dynamic_cast(haveWidget("activity")); + auto asset = dynamic_cast(haveWidget("asset-account")); + auto memo = dynamic_cast(d->m_editWidgets["memo"]); kMyMoneyEdit* value; - KMyMoneyCategory* interest = dynamic_cast(haveWidget("interest-account")); - KMyMoneyCategory* fees = dynamic_cast(haveWidget("fee-account")); + auto interest = dynamic_cast(haveWidget("interest-account")); + auto fees = dynamic_cast(haveWidget("fee-account")); // check if the current transaction has a reference to an equity account bool haveEquityAccount = false; QList::const_iterator it_s; - for (it_s = m_transaction.splits().constBegin(); !haveEquityAccount && it_s != m_transaction.splits().constEnd(); ++it_s) { + for (it_s = d->m_transaction.splits().constBegin(); !haveEquityAccount && it_s != d->m_transaction.splits().constEnd(); ++it_s) { MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId()); - if (acc.accountType() == eMyMoney::Account::Equity) + if (acc.accountType() == Account::Equity) haveEquityAccount = true; } // asset-account AccountSet aSet; aSet.clear(); - aSet.addAccountType(eMyMoney::Account::Checkings); - aSet.addAccountType(eMyMoney::Account::Savings); - aSet.addAccountType(eMyMoney::Account::Cash); - aSet.addAccountType(eMyMoney::Account::Asset); - aSet.addAccountType(eMyMoney::Account::Currency); - aSet.addAccountType(eMyMoney::Account::CreditCard); + aSet.addAccountType(Account::Checkings); + aSet.addAccountType(Account::Savings); + aSet.addAccountType(Account::Cash); + aSet.addAccountType(Account::Asset); + aSet.addAccountType(Account::Currency); + aSet.addAccountType(Account::CreditCard); if (KMyMoneyGlobalSettings::expertMode() || haveEquityAccount) - aSet.addAccountGroup(eMyMoney::Account::Equity); + aSet.addAccountGroup(Account::Equity); aSet.load(asset->selector()); // security security->setSuppressObjectCreation(false); // allow object creation on the fly aSet.clear(); - aSet.load(security->selector(), i18n("Security"), m_account.accountList(), true); + aSet.load(security->selector(), i18n("Security"), d->m_account.accountList(), true); // memo - memo->setText(m_split.memo()); - d->m_activity->m_memoText = m_split.memo(); - d->m_activity->m_memoChanged = false; + memo->setText(d->m_split.memo()); + d->m_activity->memoText() = d->m_split.memo(); + d->m_activity->memoChanged() = false; if (!isMultiSelection()) { // date - if (m_transaction.postDate().isValid()) - postDate->setDate(m_transaction.postDate()); - else if (m_lastPostDate.isValid()) - postDate->setDate(m_lastPostDate); + if (d->m_transaction.postDate().isValid()) + postDate->setDate(d->m_transaction.postDate()); + else if (d->m_lastPostDate.isValid()) + postDate->setDate(d->m_lastPostDate); else postDate->setDate(QDate::currentDate()); // security (but only if it's not the investment account) - if (m_split.accountId() != m_account.id()) { - security->completion()->setSelected(m_split.accountId()); - security->slotItemSelected(m_split.accountId()); + if (d->m_split.accountId() != d->m_account.id()) { + security->completion()->setSelected(d->m_split.accountId()); + security->slotItemSelected(d->m_split.accountId()); } // activity activity->setActivity(d->m_activity->type()); slotUpdateActivity(activity->activity()); - asset->completion()->setSelected(m_assetAccountSplit.accountId()); - asset->slotItemSelected(m_assetAccountSplit.accountId()); + asset->completion()->setSelected(d->m_assetAccountSplit.accountId()); + asset->slotItemSelected(d->m_assetAccountSplit.accountId()); // interest-account aSet.clear(); - aSet.addAccountGroup(eMyMoney::Account::Income); + aSet.addAccountGroup(Account::Income); aSet.load(interest->selector()); - setupCategoryWidget(interest, m_interestSplits, id, SLOT(slotEditInterestSplits())); + setupCategoryWidget(interest, d->m_interestSplits, id, SLOT(slotEditInterestSplits())); slotUpdateInterestVisibility(interest->currentText()); // fee-account aSet.clear(); - aSet.addAccountGroup(eMyMoney::Account::Expense); + aSet.addAccountGroup(Account::Expense); aSet.load(fees->selector()); - setupCategoryWidget(fees, m_feeSplits, id, SLOT(slotEditFeeSplits())); + setupCategoryWidget(fees, d->m_feeSplits, id, SLOT(slotEditFeeSplits())); slotUpdateFeeVisibility(fees->currentText()); // shares // don't set the value if the number of shares is zero so that // we can see the hint value = dynamic_cast(haveWidget("shares")); if (typeid(*(d->m_activity)) != typeid(Invest::Split(this))) - value->setPrecision(MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction())); + value->setPrecision(MyMoneyMoney::denomToPrec(d->m_security.smallestAccountFraction())); else value->setPrecision(-1); - if (!m_split.shares().isZero()) - value->setValue(m_split.shares().abs()); + if (!d->m_split.shares().isZero()) + value->setValue(d->m_split.shares().abs()); // price - updatePriceMode(m_split); + d->updatePriceMode(d->m_split); // fee amount value = dynamic_cast(haveWidget("fee-amount")); - value->setValue(subtotal(m_feeSplits)); + value->setValue(d->subtotal(d->m_feeSplits)); // interest amount value = dynamic_cast(haveWidget("interest-amount")); - value->setValue(-subtotal(m_interestSplits)); + value->setValue(-d->subtotal(d->m_interestSplits)); // total slotUpdateTotalAmount(); // status - if (m_split.reconcileFlag() == eMyMoney::Split::State::Unknown) - m_split.setReconcileFlag(eMyMoney::Split::State::NotReconciled); - reconcile->setState(m_split.reconcileFlag()); + if (d->m_split.reconcileFlag() == eMyMoney::Split::State::Unknown) + d->m_split.setReconcileFlag(eMyMoney::Split::State::NotReconciled); + reconcile->setState(d->m_split.reconcileFlag()); } else { postDate->loadDate(QDate()); reconcile->setState(eMyMoney::Split::State::Unknown); // We don't allow to change the activity activity->setActivity(d->m_activity->type()); slotUpdateActivity(activity->activity()); activity->setDisabled(true); // scan the list of selected transactions and check that they have // the same activity. - KMyMoneyRegister::SelectedTransactions::iterator it_t = m_transactions.begin(); - const QString& action = m_item->split().action(); - bool isNegative = m_item->split().shares().isNegative(); + KMyMoneyRegister::SelectedTransactions::iterator it_t = d->m_transactions.begin(); + const QString& action = d->m_item->split().action(); + bool isNegative = d->m_item->split().shares().isNegative(); bool allSameActivity = true; - for (it_t = m_transactions.begin(); allSameActivity && (it_t != m_transactions.end()); ++it_t) { + for (it_t = d->m_transactions.begin(); allSameActivity && (it_t != d->m_transactions.end()); ++it_t) { allSameActivity = (action == (*it_t).split().action() && (*it_t).split().shares().isNegative() == isNegative); } QStringList fields; fields << "shares" << "price" << "fee-amount" << "interest-amount"; QStringList::const_iterator it_f; for (it_f = fields.constBegin(); it_f != fields.constEnd(); ++it_f) { value = dynamic_cast(haveWidget((*it_f))); value->setText(""); value->setAllowEmpty(); } // if we have transactions with different activities, disable some more widgets if (!allSameActivity) { fields << "asset-account" << "fee-account" << "interest-account"; QStringList::const_iterator it_f; for (it_f = fields.constBegin(); it_f != fields.constEnd(); ++it_f) { haveWidget(*it_f)->setDisabled(true); } } } } QWidget* InvestTransactionEditor::firstWidget() const { - return 0; // let the creator use the first widget in the tab order + return nullptr; // let the creator use the first widget in the tab order } bool InvestTransactionEditor::isComplete(QString& reason) const { + Q_D(const InvestTransactionEditor); reason.clear(); return d->m_activity->isComplete(reason); } -MyMoneyMoney InvestTransactionEditor::subtotal(const QList& splits) const -{ - QList::const_iterator it_s; - MyMoneyMoney sum; - - for (it_s = splits.begin(); it_s != splits.end(); ++it_s) { - sum += (*it_s).value(); - } - - return sum; -} - void InvestTransactionEditor::slotUpdateSecurity(const QString& stockId) { - MyMoneyFile* file = MyMoneyFile::instance(); + Q_D(InvestTransactionEditor); + auto file = MyMoneyFile::instance(); MyMoneyAccount stock = file->account(stockId); - m_security = file->security(stock.currencyId()); - m_currency = file->security(m_security.tradingCurrency()); - bool currencyKnown = !m_currency.id().isEmpty(); + d->m_security = file->security(stock.currencyId()); + d->m_currency = file->security(d->m_security.tradingCurrency()); + bool currencyKnown = !d->m_currency.id().isEmpty(); if (!currencyKnown) { - m_currency.setTradingSymbol("???"); + d->m_currency.setTradingSymbol("???"); } else { if (typeid(*(d->m_activity)) != typeid(Invest::Split(this))) { - dynamic_cast(haveWidget("shares"))->setPrecision(MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction())); + dynamic_cast(haveWidget("shares"))->setPrecision(MyMoneyMoney::denomToPrec(d->m_security.smallestAccountFraction())); } else { dynamic_cast(haveWidget("shares"))->setPrecision(-1); } } - updatePriceMode(); + d->updatePriceMode(); d->m_activity->preloadAssetAccount(); haveWidget("shares")->setEnabled(currencyKnown); haveWidget("price")->setEnabled(currencyKnown); haveWidget("fee-amount")->setEnabled(currencyKnown); haveWidget("interest-amount")->setEnabled(currencyKnown); slotUpdateTotalAmount(); slotUpdateButtonState(); resizeForm(); } +bool InvestTransactionEditor::fixTransactionCommodity(const MyMoneyAccount& /* account */) +{ + return true; +} + + void InvestTransactionEditor::totalAmount(MyMoneyMoney& amount) const { - KMyMoneyActivityCombo* activityCombo = dynamic_cast(haveWidget("activity")); - kMyMoneyEdit* sharesEdit = dynamic_cast(haveWidget("shares")); - kMyMoneyEdit* priceEdit = dynamic_cast(haveWidget("price")); - kMyMoneyEdit* feesEdit = dynamic_cast(haveWidget("fee-amount")); - kMyMoneyEdit* interestEdit = dynamic_cast(haveWidget("interest-amount")); + auto activityCombo = dynamic_cast(haveWidget("activity")); + auto sharesEdit = dynamic_cast(haveWidget("shares")); + auto priceEdit = dynamic_cast(haveWidget("price")); + auto feesEdit = dynamic_cast(haveWidget("fee-amount")); + auto interestEdit = dynamic_cast(haveWidget("interest-amount")); - if (priceMode() == InvestTransactionEditor::PricePerTransaction) + if (priceMode() == eDialogs::PriceMode::PricePerTransaction) amount = priceEdit->value().abs(); else amount = sharesEdit->value().abs() * priceEdit->value().abs(); if (feesEdit->isVisible()) { MyMoneyMoney fee = feesEdit->value(); MyMoneyMoney factor(-1, 1); switch (activityCombo->activity()) { case eMyMoney::Split::InvestmentTransactionType::BuyShares: case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend: factor = MyMoneyMoney::ONE; break; default: break; } amount += (fee * factor); } if (interestEdit->isVisible()) { MyMoneyMoney interest = interestEdit->value(); MyMoneyMoney factor(1, 1); switch (activityCombo->activity()) { case eMyMoney::Split::InvestmentTransactionType::BuyShares: factor = MyMoneyMoney::MINUS_ONE; break; default: break; } amount += (interest * factor); } } void InvestTransactionEditor::slotUpdateTotalAmount() { + Q_D(InvestTransactionEditor); QLabel* total = dynamic_cast(haveWidget("total")); if (total && total->isVisible()) { MyMoneyMoney amount; totalAmount(amount); - total->setText(amount.convert(m_currency.smallestAccountFraction(), static_cast(m_security.roundingMethod())) - .formatMoney(m_currency.tradingSymbol(), MyMoneyMoney::denomToPrec(m_currency.smallestAccountFraction()))); + total->setText(amount.convert(d->m_currency.smallestAccountFraction(), static_cast(d->m_security.roundingMethod())) + .formatMoney(d->m_currency.tradingSymbol(), MyMoneyMoney::denomToPrec(d->m_currency.smallestAccountFraction()))); } } void InvestTransactionEditor::slotTransactionContainerGeometriesUpdated() { + Q_D(InvestTransactionEditor); // when the geometries of the transaction container are updated some edit widgets that were // previously hidden are being shown (see QAbstractItemView::updateEditorGeometries) so we // need to update the activity with the current activity in order to show only the widgets // which are needed by the current activity slotUpdateActivity(d->m_activity->type()); } void InvestTransactionEditor::slotUpdateActivity(eMyMoney::Split::InvestmentTransactionType activity) { + Q_D(InvestTransactionEditor); // create new activity object if required - activityFactory(activity); + d->activityFactory(activity); // hide all dynamic widgets d->hideCategory("interest-account"); d->hideCategory("fee-account"); QStringList dynwidgets; dynwidgets << "total-label" << "asset-label" << "fee-label" << "fee-amount-label" << "interest-label" << "interest-amount-label" << "price-label" << "shares-label"; // hiding labels works by clearing them. hide() does not do the job // as the underlying text in the QTable object will shine through QStringList::const_iterator it_s; for (it_s = dynwidgets.constBegin(); it_s != dynwidgets.constEnd(); ++it_s) { QLabel* w = dynamic_cast(haveWidget(*it_s)); if (w) w->setText(" "); } // real widgets can be hidden dynwidgets.clear(); dynwidgets << "asset-account" << "interest-amount" << "fee-amount" << "shares" << "price" << "total"; for (it_s = dynwidgets.constBegin(); it_s != dynwidgets.constEnd(); ++it_s) { QWidget* w = haveWidget(*it_s); if (w) w->hide(); } d->m_activity->showWidgets(); d->m_activity->preloadAssetAccount(); if (KMyMoneyCategory* cat = dynamic_cast(haveWidget("interest-account"))) { if (cat->parentWidget()->isVisible()) slotUpdateInterestVisibility(cat->currentText()); else cat->splitButton()->hide(); } if (KMyMoneyCategory* cat = dynamic_cast(haveWidget("fee-account"))) { if (cat->parentWidget()->isVisible()) slotUpdateFeeVisibility(cat->currentText()); else cat->splitButton()->hide(); } } -InvestTransactionEditor::priceModeE InvestTransactionEditor::priceMode() const +eDialogs::PriceMode InvestTransactionEditor::priceMode() const { - priceModeE mode = static_cast(Price); - KMyMoneySecurity* sec = dynamic_cast(m_editWidgets["security"]); + Q_D(const InvestTransactionEditor); + eDialogs::PriceMode mode = static_cast(eDialogs::PriceMode::Price); + KMyMoneySecurity* sec = dynamic_cast(d->m_editWidgets["security"]); QString accId; if (!sec->currentText().isEmpty()) { accId = sec->selectedItem(); if (accId.isEmpty()) - accId = m_account.id(); + accId = d->m_account.id(); } - while (!accId.isEmpty() && mode == Price) { + while (!accId.isEmpty() && mode == eDialogs::PriceMode::Price) { MyMoneyAccount acc = MyMoneyFile::instance()->account(accId); if (acc.value("priceMode").isEmpty()) accId = acc.parentAccountId(); else - mode = static_cast(acc.value("priceMode").toInt()); + mode = static_cast(acc.value("priceMode").toInt()); } // if mode is still then use that - if (mode == Price) - mode = PricePerShare; + if (mode == eDialogs::PriceMode::Price) + mode = eDialogs::PriceMode::PricePerShare; return mode; } +MyMoneySecurity InvestTransactionEditor::security() const +{ + Q_D(const InvestTransactionEditor); + return d->m_security; +} + +QList InvestTransactionEditor::feeSplits() const +{ + Q_D(const InvestTransactionEditor); + return d->m_feeSplits; +} + +QList InvestTransactionEditor::interestSplits() const +{ + Q_D(const InvestTransactionEditor); + return d->m_interestSplits; +} + bool InvestTransactionEditor::setupPrice(const MyMoneyTransaction& t, MyMoneySplit& split) { - MyMoneyFile* file = MyMoneyFile::instance(); + Q_D(InvestTransactionEditor); + auto file = MyMoneyFile::instance(); MyMoneyAccount acc = file->account(split.accountId()); MyMoneySecurity toCurrency(file->security(acc.currencyId())); int fract = acc.fraction(); if (acc.currencyId() != t.commodity()) { if (acc.currencyId().isEmpty()) acc.setCurrencyId(t.commodity()); QMap::Iterator it_p; QString key = t.commodity() + '-' + acc.currencyId(); - it_p = m_priceInfo.find(key); + it_p = d->m_priceInfo.find(key); // if it's not found, then collect it from the user first MyMoneyMoney price; - if (it_p == m_priceInfo.end()) { + if (it_p == d->m_priceInfo.end()) { MyMoneySecurity fromCurrency = file->security(t.commodity()); MyMoneyMoney fromValue, toValue; fromValue = split.value(); const MyMoneyPrice &priceInfo = MyMoneyFile::instance()->price(fromCurrency.id(), toCurrency.id(), t.postDate()); toValue = split.value() * priceInfo.rate(toCurrency.id()); QPointer calc = new KCurrencyCalculator(fromCurrency, toCurrency, fromValue, toValue, t.postDate(), fract, - m_regForm); + d->m_regForm); if (calc->exec() == QDialog::Rejected) { delete calc; return false; } price = calc->price(); delete calc; - m_priceInfo[key] = price; + d->m_priceInfo[key] = price; } else { price = (*it_p); } // update shares if the transaction commodity is the currency // of the current selected account split.setShares(split.value() * price); } else { split.setShares(split.value()); } return true; } bool InvestTransactionEditor::createTransaction(MyMoneyTransaction& t, const MyMoneyTransaction& torig, const MyMoneySplit& sorig, bool /* skipPriceDialog */) { - MyMoneyFile* file = MyMoneyFile::instance(); + Q_D(InvestTransactionEditor); + auto file = MyMoneyFile::instance(); // we start with the previous values, make sure we can add them later on t = torig; MyMoneySplit s0 = sorig; s0.clearId(); - KMyMoneySecurity* sec = dynamic_cast(m_editWidgets["security"]); + KMyMoneySecurity* sec = dynamic_cast(d->m_editWidgets["security"]); if (!isMultiSelection() || (isMultiSelection() && !sec->currentText().isEmpty())) { QString securityId = sec->selectedItem(); if (!securityId.isEmpty()) { s0.setAccountId(securityId); MyMoneyAccount stockAccount = file->account(securityId); QString currencyId = stockAccount.currencyId(); MyMoneySecurity security = file->security(currencyId); t.setCommodity(security.tradingCurrency()); } else { - s0.setAccountId(m_account.id()); - t.setCommodity(m_account.currencyId()); + s0.setAccountId(d->m_account.id()); + t.setCommodity(d->m_account.currencyId()); } } // extract price info from original transaction - m_priceInfo.clear(); + d->m_priceInfo.clear(); QList::const_iterator it_s; if (!torig.id().isEmpty()) { for (it_s = torig.splits().begin(); it_s != torig.splits().end(); ++it_s) { if ((*it_s).id() != sorig.id()) { MyMoneyAccount cat = file->account((*it_s).accountId()); - if (cat.currencyId() != m_account.currencyId()) { + if (cat.currencyId() != d->m_account.currencyId()) { if (cat.currencyId().isEmpty()) - cat.setCurrencyId(m_account.currencyId()); + cat.setCurrencyId(d->m_account.currencyId()); if (!(*it_s).shares().isZero() && !(*it_s).value().isZero()) { - m_priceInfo[cat.currencyId()] = ((*it_s).shares() / (*it_s).value()).reduce(); + d->m_priceInfo[cat.currencyId()] = ((*it_s).shares() / (*it_s).value()).reduce(); } } } } } t.removeSplits(); - kMyMoneyDateInput* postDate = dynamic_cast(m_editWidgets["postdate"]); + kMyMoneyDateInput* postDate = dynamic_cast(d->m_editWidgets["postdate"]); if (postDate->date().isValid()) { t.setPostDate(postDate->date()); } // memo and number field are special: if we have multiple transactions selected // and the edit field is empty, we treat it as "not modified". // FIXME a better approach would be to have a 'dirty' flag with the widgets // which identifies if the originally loaded value has been modified // by the user - KTextEdit* memo = dynamic_cast(m_editWidgets["memo"]); + KTextEdit* memo = dynamic_cast(d->m_editWidgets["memo"]); if (memo) { - if (!isMultiSelection() || (isMultiSelection() && d->m_activity->m_memoChanged)) + if (!isMultiSelection() || (isMultiSelection() && d->m_activity->memoChanged())) s0.setMemo(memo->toPlainText()); } MyMoneySplit assetAccountSplit; QList feeSplits; QList interestSplits; MyMoneySecurity security, currency; eMyMoney::Split::InvestmentTransactionType transactionType; // extract the splits from the original transaction KMyMoneyUtils::dissectTransaction(torig, sorig, assetAccountSplit, feeSplits, interestSplits, security, currency, transactionType); // check if the trading currency is the same if the security has changed // in case it differs, check that we have a price (request from user) // and convert all splits // TODO // do the conversions here // TODO // keep the current activity object and create a new one // that can be destroyed later on - Activity* activity = d->m_activity; + auto activity = d->m_activity; d->m_activity = 0; // make sure we create a new one - activityFactory(activity->type()); + d->activityFactory(activity->type()); // if the activity is not set in the combo widget, we keep // the one which is used in the original transaction - KMyMoneyActivityCombo* activityCombo = dynamic_cast(haveWidget("activity")); + auto activityCombo = dynamic_cast(haveWidget("activity")); if (activityCombo->activity() == eMyMoney::Split::InvestmentTransactionType::UnknownTransactionType) { - activityFactory(transactionType); + d->activityFactory(transactionType); } // if we mark the split reconciled here, we'll use today's date if no reconciliation date is given - KMyMoneyReconcileCombo* status = dynamic_cast(m_editWidgets["status"]); + auto status = dynamic_cast(d->m_editWidgets["status"]); if (status->state() != eMyMoney::Split::State::Unknown) s0.setReconcileFlag(status->state()); if (s0.reconcileFlag() == eMyMoney::Split::State::Reconciled && !s0.reconcileDate().isValid()) s0.setReconcileDate(QDate::currentDate()); // call the creation logic for the current selected activity - bool rc = d->m_activity->createTransaction(t, s0, assetAccountSplit, feeSplits, m_feeSplits, interestSplits, m_interestSplits, security, currency); + bool rc = d->m_activity->createTransaction(t, s0, assetAccountSplit, feeSplits, d->m_feeSplits, interestSplits, d->m_interestSplits, security, currency); // now switch back to the original activity delete d->m_activity; d->m_activity = activity; // add the splits to the transaction if (rc) { if (security.name().isEmpty()) // new transaction has no security filled... security = file->security(file->account(s0.accountId()).currencyId()); // ...so fetch it from s0 split QList resultSplits; // concatenates splits for easy processing if (!assetAccountSplit.accountId().isEmpty()) resultSplits.append(assetAccountSplit); if (!feeSplits.isEmpty()) resultSplits.append(feeSplits); if (!interestSplits.isEmpty()) resultSplits.append(interestSplits); AlkValue::RoundingMethod roundingMethod = AlkValue::RoundRound; if (security.roundingMethod() != AlkValue::RoundNever) roundingMethod = security.roundingMethod(); int currencyFraction = currency.smallestAccountFraction(); int securityFraction = security.smallestAccountFraction(); // assuming that all non-stock splits are monetary foreach (auto split, resultSplits) { split.clearId(); split.setShares(split.shares().convertDenominator(currencyFraction, roundingMethod)); split.setValue(split.value().convertDenominator(currencyFraction, roundingMethod)); t.addSplit(split); } s0.setShares(s0.shares().convertDenominator(securityFraction, roundingMethod)); // only shares variable from stock split isn't evaluated in currency s0.setValue(s0.value().convertDenominator(currencyFraction, roundingMethod)); t.addSplit(s0); } return rc; } -void InvestTransactionEditor::updatePriceMode(const MyMoneySplit& split) -{ - QLabel* label = dynamic_cast(haveWidget("price-label")); - if (label) { - kMyMoneyEdit* sharesEdit = dynamic_cast(haveWidget("shares")); - kMyMoneyEdit* priceEdit = dynamic_cast(haveWidget("price")); - MyMoneyMoney price; - if (!split.id().isEmpty()) - price = split.price().reduce(); - else - price = priceEdit->value().abs(); - - if (priceMode() == PricePerTransaction) { - priceEdit->setPrecision(m_currency.pricePrecision()); - label->setText(i18n("Transaction amount")); - if (!sharesEdit->value().isZero()) - priceEdit->setValue(sharesEdit->value().abs() * price); - - } else if (priceMode() == PricePerShare) { - priceEdit->setPrecision(m_security.pricePrecision()); - label->setText(i18n("Price/Share")); - priceEdit->setValue(price); - } else - priceEdit->setValue(price); - } -} - void InvestTransactionEditor::setupFinalWidgets() { addFinalWidget(haveWidget("memo")); } void InvestTransactionEditor::slotUpdateInvestMemoState() { - KTextEdit* memo = dynamic_cast(m_editWidgets["memo"]); + Q_D(InvestTransactionEditor); + auto memo = dynamic_cast(d->m_editWidgets["memo"]); if (memo) { - d->m_activity->m_memoChanged = (memo->toPlainText() != d->m_activity->m_memoText); + d->m_activity->memoChanged() = (memo->toPlainText() != d->m_activity->memoText()); } } diff --git a/kmymoney/dialogs/investtransactioneditor.h b/kmymoney/dialogs/investtransactioneditor.h index 16f2f1e48..e38eae9fe 100644 --- a/kmymoney/dialogs/investtransactioneditor.h +++ b/kmymoney/dialogs/investtransactioneditor.h @@ -1,189 +1,155 @@ /*************************************************************************** investtransactioneditor.h ---------- begin : Fri Dec 15 2006 copyright : (C) 2006 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef INVESTTRANSACTIONEDITOR_H #define INVESTTRANSACTIONEDITOR_H // ---------------------------------------------------------------------------- // QT Includes -#include - // ---------------------------------------------------------------------------- // KDE Includes - // ---------------------------------------------------------------------------- // Project Includes #include "transactioneditor.h" +class MyMoneyMoney; +class MyMoneySecurity; + +namespace eDialogs { enum class PriceMode; } + +namespace KMyMoneyRegister { class InvestTransaction; } + +namespace eMyMoney { namespace Split { + enum class InvestmentTransactionType; } } + +class InvestTransactionEditorPrivate; class InvestTransactionEditor : public TransactionEditor { - friend class InvestTransactionEditorPrivate; - Q_OBJECT + Q_DISABLE_COPY(InvestTransactionEditor) public: - typedef enum { - Price = 0, - PricePerShare, - PricePerTransaction - } priceModeE; - InvestTransactionEditor(); - InvestTransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::InvestTransaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate); - virtual ~InvestTransactionEditor(); + explicit InvestTransactionEditor(TransactionEditorContainer* regForm, + KMyMoneyRegister::InvestTransaction* item, + const KMyMoneyRegister::SelectedTransactions& list, + const QDate& lastPostDate); + ~InvestTransactionEditor() override; /** * This method returns information about the completeness of the data * entered. This can be used to control the availability of the * 'Enter transaction' action. * * @retval true if entering the transaction into the engine * @retval false if not enough information is present to enter the * transaction into the engine * * @param reason will be filled with a string about the reason why the * completeness is not reached. Empty if the return value * is @c true. * * @sa transactionDataSufficient() */ - virtual bool isComplete(QString& reason) const; + bool isComplete(QString& reason) const override; - virtual QWidget* firstWidget() const; + QWidget* firstWidget() const override; - virtual bool fixTransactionCommodity(const MyMoneyAccount& /* account */) { - return true; - } + bool fixTransactionCommodity(const MyMoneyAccount& /* account */) override; void totalAmount(MyMoneyMoney& amount) const; bool setupPrice(const MyMoneyTransaction& t, MyMoneySplit& split); /** * This method creates a transaction based on the contents of the current widgets, * the splits in m_split in single selection mode or an existing transaction/split * and the contents of the widgets in multi selection mode. * * The split referencing the current account is returned as the first split in the * transaction's split list. * * @param t reference to created transaction * @param torig the original transaction * @param sorig the original split * * @param skipPriceDialog if @p true the user will not be requested for price information * (defaults to @p false) * * @return @p false if aborted by user, @p true otherwise * * @note Usually not used directly. If unsure, use enterTransactions() instead. */ - bool createTransaction(MyMoneyTransaction& t, const MyMoneyTransaction& torig, const MyMoneySplit& sorig, bool skipPriceDialog = false); - - priceModeE priceMode() const; + bool createTransaction(MyMoneyTransaction& t, + const MyMoneyTransaction& torig, + const MyMoneySplit& sorig, + bool skipPriceDialog = false) override; - const MyMoneySecurity& security() const { - return m_security; - } + eDialogs::PriceMode priceMode() const; - const QList& feeSplits() const { - return m_feeSplits; - } + MyMoneySecurity security() const; - const QList& interestSplits() const { - return m_interestSplits; - } + QList feeSplits() const; + QList interestSplits() const; protected slots: void slotCreateSecurity(const QString& name, QString& id); void slotCreateFeeCategory(const QString& name, QString& id); void slotCreateInterestCategory(const QString& name, QString& id); int slotEditInterestSplits(); int slotEditFeeSplits(); void slotReloadEditWidgets(); void slotUpdateActivity(eMyMoney::Split::InvestmentTransactionType); void slotUpdateSecurity(const QString& stockId); void slotUpdateInterestCategory(const QString& id); void slotUpdateInterestVisibility(const QString&); void slotUpdateFeeCategory(const QString& id); void slotUpdateFeeVisibility(const QString&); void slotUpdateTotalAmount(); void slotTransactionContainerGeometriesUpdated(); void slotUpdateInvestMemoState(); protected: /** * This method creates all necessary widgets for this transaction editor. * All signals will be connected to the relevant slots. */ - void createEditWidgets(); + void createEditWidgets() override; /** * This method (re-)loads the widgets with the transaction information * contained in @a m_transaction and @a m_split. * * @param action preset the edit wigdets for @a action if no transaction * is present */ - void loadEditWidgets(KMyMoneyRegister::Action action = KMyMoneyRegister::ActionNone); - - void activityFactory(eMyMoney::Split::InvestmentTransactionType type); - - MyMoneyMoney subtotal(const QList& splits) const; + void loadEditWidgets(KMyMoneyRegister::Action action) override; + void loadEditWidgets() override; - /** - * This method creates a transaction to be used for the split fee/interest editor. - * It has a reference to a phony account and the splits contained in @a splits . - */ - bool createPseudoTransaction(MyMoneyTransaction& t, const QList& splits); - - /** - * Convenience method used by slotEditInterestSplits() and slotEditFeeSplits(). - * - * @param categoryWidgetName name of the category widget - * @param amountWidgetName name of the amount widget - * @param splits the splits that make up the transaction to be edited - * @param isIncome @c false for fees, @c true for interest - * @param slotEditSplits name of the slot to be connected to the focusIn signal of the - * category widget named @p categoryWidgetName in case of multiple splits - * in @p splits . - */ - int editSplits(const QString& categoryWidgetName, const QString& amountWidgetName, QList& splits, bool isIncome, const char* slotEditSplits); - - void updatePriceMode(const MyMoneySplit& split = MyMoneySplit()); - - void setupFinalWidgets(); + void setupFinalWidgets() override; private: - MyMoneySplit m_assetAccountSplit; - QList m_interestSplits; - QList m_feeSplits; - MyMoneySecurity m_security; - MyMoneySecurity m_currency; - eMyMoney::Split::InvestmentTransactionType m_transactionType; - /// \internal d-pointer class. - class Private; - /// \internal d-pointer instance. - Private* const d; + Q_DECLARE_PRIVATE(InvestTransactionEditor) }; #endif // INVESTTRANSACTIONEDITOR_H diff --git a/kmymoney/dialogs/kaccountselectdlg.cpp b/kmymoney/dialogs/kaccountselectdlg.cpp index 0bfaa5fc0..8c45a189b 100644 --- a/kmymoney/dialogs/kaccountselectdlg.cpp +++ b/kmymoney/dialogs/kaccountselectdlg.cpp @@ -1,197 +1,251 @@ /*************************************************************************** kaccountselectdlg.cpp - description ------------------- begin : Mon Feb 10 2003 copyright : (C) 2000-2003 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kaccountselectdlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kaccountselectdlg.h" + +#include "mymoneyaccount.h" #include "mymoneyfile.h" #include "kmymoneycategory.h" #include "kmymoneyaccountselector.h" #include <../kmymoney.h> +#include "dialogenums.h" #include "icons/icons.h" using namespace Icons; -KAccountSelectDlg::KAccountSelectDlg(const KMyMoneyUtils::categoryTypeE accountType, const QString& purpose, QWidget *parent) - : KAccountSelectDlgDecl(parent), - m_purpose(purpose), - m_accountType(accountType), +class KAccountSelectDlgPrivate +{ + Q_DISABLE_COPY(KAccountSelectDlgPrivate) + +public: + KAccountSelectDlgPrivate() : + ui(new Ui::KAccountSelectDlg), m_aborted(false) + { + } + + ~KAccountSelectDlgPrivate() + { + delete ui; + } + + Ui::KAccountSelectDlg *ui; + QString m_purpose; + MyMoneyAccount m_account; + int m_mode; // 0 - select or create, 1 - create only + eDialogs::Category m_accountType; + bool m_aborted; +}; + +KAccountSelectDlg::KAccountSelectDlg(const eDialogs::Category accountType, const QString& purpose, QWidget *parent) : + QDialog(parent), + d_ptr(new KAccountSelectDlgPrivate) { + Q_D(KAccountSelectDlg); + d->ui->setupUi(this); + d->m_purpose = purpose; + d->m_accountType = accountType; // Hide the abort button. It needs to be shown on request by the caller // using showAbortButton() - m_kButtonAbort->hide(); + d->ui->m_kButtonAbort->hide(); slotReloadWidget(); KGuiItem skipButtonItem(i18n("&Skip"), QIcon::fromTheme(g_Icons[Icon::MediaSkipForward]), i18n("Skip this transaction"), i18n("Use this to skip importing this transaction and proceed with the next one.")); - KGuiItem::assign(m_qbuttonCancel, skipButtonItem); + KGuiItem::assign(d->ui->m_qbuttonCancel, skipButtonItem); KGuiItem createButtenItem(i18n("&Create..."), QIcon::fromTheme(g_Icons[Icon::DocumentNew]), i18n("Create a new account/category"), i18n("Use this to add a new account/category to the file")); - KGuiItem::assign(m_createButton, createButtenItem); - KGuiItem::assign(m_qbuttonOk, KStandardGuiItem::ok()); + KGuiItem::assign(d->ui->m_createButton, createButtenItem); + KGuiItem::assign(d->ui->m_qbuttonOk, KStandardGuiItem::ok()); KGuiItem abortButtenItem(i18n("&Abort"), QIcon::fromTheme(g_Icons[Icon::DialogCancel]), i18n("Abort the import operation and dismiss all changes"), i18n("Use this to abort the import. Your financial data will be in the state before you started the QIF import.")); - KGuiItem::assign(m_kButtonAbort, abortButtenItem); + KGuiItem::assign(d->ui->m_kButtonAbort, abortButtenItem); + connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, this, &KAccountSelectDlg::slotReloadWidget); - connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotReloadWidget())); - - connect(m_createButton, SIGNAL(clicked()), this, SLOT(slotCreateAccount())); - connect(m_qbuttonOk, SIGNAL(clicked()), this, SLOT(accept())); - connect(m_qbuttonCancel, SIGNAL(clicked()), this, SLOT(reject())); - connect(m_kButtonAbort, SIGNAL(clicked()), this, SLOT(abort())); + connect(d->ui->m_createButton, &QAbstractButton::clicked, this, &KAccountSelectDlg::slotCreateAccount); + connect(d->ui->m_qbuttonOk, &QAbstractButton::clicked, this, &QDialog::accept); + connect(d->ui->m_qbuttonCancel, &QAbstractButton::clicked, this, &QDialog::reject); + connect(d->ui->m_kButtonAbort, &QAbstractButton::clicked, this, &KAccountSelectDlg::abort); } KAccountSelectDlg::~KAccountSelectDlg() { + Q_D(KAccountSelectDlg); + delete d; } void KAccountSelectDlg::slotReloadWidget() { + Q_D(KAccountSelectDlg); AccountSet set; - if (m_accountType & KMyMoneyUtils::asset) + if (d->m_accountType & eDialogs::Category::asset) set.addAccountGroup(eMyMoney::Account::Asset); - if (m_accountType & KMyMoneyUtils::liability) + if (d->m_accountType & eDialogs::Category::liability) set.addAccountGroup(eMyMoney::Account::Liability); - if (m_accountType & KMyMoneyUtils::income) + if (d->m_accountType & eDialogs::Category::income) set.addAccountGroup(eMyMoney::Account::Income); - if (m_accountType & KMyMoneyUtils::expense) + if (d->m_accountType & eDialogs::Category::expense) set.addAccountGroup(eMyMoney::Account::Expense); - if (m_accountType & KMyMoneyUtils::equity) + if (d->m_accountType & eDialogs::Category::equity) set.addAccountGroup(eMyMoney::Account::Equity); - if (m_accountType & KMyMoneyUtils::checking) + if (d->m_accountType & eDialogs::Category::checking) set.addAccountType(eMyMoney::Account::Checkings); - if (m_accountType & KMyMoneyUtils::savings) + if (d->m_accountType & eDialogs::Category::savings) set.addAccountType(eMyMoney::Account::Savings); - if (m_accountType & KMyMoneyUtils::investment) + if (d->m_accountType & eDialogs::Category::investment) set.addAccountType(eMyMoney::Account::Investment); - if (m_accountType & KMyMoneyUtils::creditCard) + if (d->m_accountType & eDialogs::Category::creditCard) set.addAccountType(eMyMoney::Account::CreditCard); - set.load(m_accountSelector->selector()); + set.load(d->ui->m_accountSelector->selector()); } void KAccountSelectDlg::setDescription(const QString& msg) { - m_descLabel->setText(msg); + Q_D(KAccountSelectDlg); + d->ui->m_descLabel->setText(msg); } void KAccountSelectDlg::setHeader(const QString& msg) { - m_headerLabel->setText(msg); + Q_D(KAccountSelectDlg); + d->ui->m_headerLabel->setText(msg); } void KAccountSelectDlg::setAccount(const MyMoneyAccount& account, const QString& id) { - m_account = account; - m_accountSelector->setSelectedItem(id); + Q_D(KAccountSelectDlg); + d->m_account = account; + d->ui->m_accountSelector->setSelectedItem(id); } void KAccountSelectDlg::slotCreateInstitution() { kmymoney->slotInstitutionNew(); } void KAccountSelectDlg::slotCreateAccount() { - if (!(m_accountType & (KMyMoneyUtils::expense | KMyMoneyUtils::income))) { - kmymoney->slotAccountNew(m_account); - if (!m_account.id().isEmpty()) { + Q_D(KAccountSelectDlg); + if (!((int)d->m_accountType & ((int)eDialogs::Category::expense | (int)eDialogs::Category::income))) { + kmymoney->slotAccountNew(d->m_account); + if (!d->m_account.id().isEmpty()) { slotReloadWidget(); - m_accountSelector->setSelectedItem(m_account.id()); + d->ui->m_accountSelector->setSelectedItem(d->m_account.id()); accept(); } } else { - if (m_account.accountType() == eMyMoney::Account::Expense) - kmymoney->createCategory(m_account, MyMoneyFile::instance()->expense()); + if (d->m_account.accountType() == eMyMoney::Account::Expense) + kmymoney->createCategory(d->m_account, MyMoneyFile::instance()->expense()); else - kmymoney->createCategory(m_account, MyMoneyFile::instance()->income()); - if (!m_account.id().isEmpty()) { + kmymoney->createCategory(d->m_account, MyMoneyFile::instance()->income()); + if (!d->m_account.id().isEmpty()) { slotReloadWidget(); - m_accountSelector->setSelectedItem(m_account.id()); + d->ui->m_accountSelector->setSelectedItem(d->m_account.id()); accept(); } } } void KAccountSelectDlg::abort() { - m_aborted = true; + Q_D(KAccountSelectDlg); + d->m_aborted = true; reject(); } void KAccountSelectDlg::setMode(const int mode) { - m_mode = mode ? 1 : 0; + Q_D(KAccountSelectDlg); + d->m_mode = mode ? 1 : 0; } void KAccountSelectDlg::showAbortButton(const bool visible) { - m_kButtonAbort->setVisible(visible); + Q_D(KAccountSelectDlg); + d->ui->m_kButtonAbort->setVisible(visible); +} + +bool KAccountSelectDlg::aborted() const +{ + Q_D(const KAccountSelectDlg); + return d->m_aborted; +} + +void KAccountSelectDlg::hideQifEntry() +{ + Q_D(KAccountSelectDlg); + d->ui->m_qifEntry->hide(); } int KAccountSelectDlg::exec() { + Q_D(KAccountSelectDlg); int rc = Rejected; - if (m_mode == 1) { + if (d->m_mode == 1) { slotCreateAccount(); rc = result(); } if (rc != Accepted) { - m_createButton->setFocus(); - rc = KAccountSelectDlgDecl::exec(); + d->ui->m_createButton->setFocus(); + rc = QDialog::exec(); } return rc; } -const QString& KAccountSelectDlg::selectedAccount() const +QString KAccountSelectDlg::selectedAccount() const { - return m_accountSelector->selectedItem(); + Q_D(const KAccountSelectDlg); + return d->ui->m_accountSelector->selectedItem(); } diff --git a/kmymoney/dialogs/kaccountselectdlg.h b/kmymoney/dialogs/kaccountselectdlg.h index 9482a9820..f14397b79 100644 --- a/kmymoney/dialogs/kaccountselectdlg.h +++ b/kmymoney/dialogs/kaccountselectdlg.h @@ -1,164 +1,156 @@ /*************************************************************************** kaccountselectdlg.h - description ------------------- begin : Mon Feb 10 2003 copyright : (C) 2000-2003 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KACCOUNTSELECTDLG_H #define KACCOUNTSELECTDLG_H // ---------------------------------------------------------------------------- // QT Includes -#include +#include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "mymoneyaccount.h" -#include "kmymoneyutils.h" -#include "ui_kaccountselectdlgdecl.h" - /** * @author Thomas Baumgart */ +class MyMoneyAccount; -class KAccountSelectDlgDecl : public QDialog, public Ui::KAccountSelectDlgDecl -{ -public: - KAccountSelectDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; +namespace eDialogs { enum Category : int; } -class KAccountSelectDlg : public KAccountSelectDlgDecl +class KAccountSelectDlgPrivate; +class KAccountSelectDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KAccountSelectDlg) + public: - explicit KAccountSelectDlg(const KMyMoneyUtils::categoryTypeE type, const QString& purpose = "General", QWidget *parent = 0); + explicit KAccountSelectDlg(const eDialogs::Category type, const QString& purpose, QWidget *parent = nullptr); ~KAccountSelectDlg(); /** * This method is used to setup the descriptive text in the account * selection dialog box. The @p msg should contain a descriptive * text about the purpose of the dialog and it's options. * * @param msg const reference to QString object containing the text. */ void setDescription(const QString& msg); /** * This method is used to setup the buddy text of the account * selection box. the @p msg should contain a short text * which is placed above the selection box with the account * names. * * @param msg const reference to QString object containing the text. */ void setHeader(const QString& msg); /** * This method is used to pass information to the account selection * dialog which will be used as initial selection in the account * selection combo box and during account creation. * * @param account MyMoneyAccount filled with the relevant and available information * @param id account id to be used. */ void setAccount(const MyMoneyAccount& account, const QString& id); /** * This method returns the name of the selected account in the combo box. * * @return QString containing the id of the selected account */ - const QString& selectedAccount() const; + QString selectedAccount() const; /** * This method is used to set the mode of the dialog. Two modes * are supplied: a) select or create and b) create only. * If @p mode is 0, select or create is selected, otherwise create only * is selected. * * @param mode selected mode */ void setMode(const int mode); /** * This method allows to control the visibilty of the abort button * in this dialog according to the parameter @p visible. * * @param visible @p true shows the abort button, @p false hides it. */ void showAbortButton(const bool visible); /** * This method is used to determine if the user pressed the 'Skip' or * the 'Abort' button. The return value is valid only, if the exec() * function of the dialog returns false. * * @retval false Dialog was left using the 'Skip' button * @retval true Dialog was left using the 'Abort' button */ - bool aborted() const { - return m_aborted; - }; + bool aborted() const; + + void hideQifEntry(); public slots: /** * Reimplemented from QDialog */ - int exec(); + int exec() override; protected slots: /** * This slot is used to fire up the new account wizard and preset it * with the values found in m_account. If an account was created using * the wizard, this will be the selected account. */ void slotCreateAccount(); /** * This slot is used to fire up the new institution dialog */ void slotCreateInstitution(); /** * This slot is used to react on the abort button */ void abort(); /** * This is the slot which will be called if the engine data is changed. */ void slotReloadWidget(); private: - QString m_purpose; - MyMoneyAccount m_account; - int m_mode; // 0 - select or create, 1 - create only - KMyMoneyUtils::categoryTypeE m_accountType; - bool m_aborted; + KAccountSelectDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KAccountSelectDlg) }; #endif diff --git a/kmymoney/dialogs/kaccountselectdlgdecl.ui b/kmymoney/dialogs/kaccountselectdlg.ui similarity index 98% rename from kmymoney/dialogs/kaccountselectdlgdecl.ui rename to kmymoney/dialogs/kaccountselectdlg.ui index f1323423f..197757c51 100644 --- a/kmymoney/dialogs/kaccountselectdlgdecl.ui +++ b/kmymoney/dialogs/kaccountselectdlg.ui @@ -1,213 +1,213 @@ - KAccountSelectDlgDecl - + KAccountSelectDlg + Qt::WindowModal 0 0 651 434 Account selection true 6 11 11 11 11 false QTextEdit::NoWrap true false Create Qt::Horizontal QSizePolicy::Expanding 110 20 true Account to import to false Qt::Vertical QSizePolicy::Expanding 16 20 QFrame::HLine QFrame::Sunken 6 0 0 0 0 &Abort Qt::Horizontal QSizePolicy::Expanding 160 0 OK &Skip KComboBox QComboBox
kcombobox.h
KTextEdit QTextEdit
ktextedit.h
KMyMoneyCategory KComboBox
kmymoneycategory.h
diff --git a/kmymoney/dialogs/kavailablecurrencydlg.cpp b/kmymoney/dialogs/kavailablecurrencydlg.cpp index ee4322b85..07dba60ad 100644 --- a/kmymoney/dialogs/kavailablecurrencydlg.cpp +++ b/kmymoney/dialogs/kavailablecurrencydlg.cpp @@ -1,99 +1,99 @@ /*************************************************************************** kavailablecurrencydlg.cpp - description ------------------- begin : Sat Apr 01 2017 copyright : (C) 2017 Ł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. * * * ***************************************************************************/ #include "kavailablecurrencydlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes #include "mymoneyfile.h" #include "ui_kavailablecurrencydlg.h" #include "mymoneysecurity.h" KAvailableCurrencyDlg::KAvailableCurrencyDlg(QWidget *parent) : ui(new Ui::KAvailableCurrencyDlg) { Q_UNUSED(parent); ui->setupUi(this); m_searchWidget = new KTreeWidgetSearchLineWidget(this, ui->m_currencyList); m_searchWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); ui->verticalLayout->insertWidget(0, m_searchWidget); - connect(ui->m_currencyList, SIGNAL(itemSelectionChanged()), this, SLOT(slotItemSelectionChanged())); + connect(ui->m_currencyList, &QTreeWidget::itemSelectionChanged, this, &KAvailableCurrencyDlg::slotItemSelectionChanged); slotLoadCurrencies(); //resize the column widths - for (int i = 0; i < 3; ++i) + for (auto i = 0; i < 3; ++i) ui->m_currencyList->resizeColumnToContents(i); m_searchWidget->setFocus(); } KAvailableCurrencyDlg::~KAvailableCurrencyDlg() { delete ui; } void KAvailableCurrencyDlg::slotLoadCurrencies() { QList list = MyMoneyFile::instance()->availableCurrencyList(); QList currencies = MyMoneyFile::instance()->currencyList(); foreach (auto currency, currencies) { int idx = list.indexOf(currency); if (idx != -1) list.removeAt(idx); } QList::ConstIterator it; // construct a transparent 16x16 pixmap QPixmap empty(16, 16); QBitmap mask(16, 16); mask.clear(); empty.setMask(mask); ui->m_currencyList->clear(); for (it = list.constBegin(); it != list.constEnd(); ++it) { QTreeWidgetItem *p = new QTreeWidgetItem(ui->m_currencyList); p->setText(0, (*it).name()); p->setData(0, Qt::UserRole, QVariant::fromValue(*it)); p->setData(0, Qt::DecorationRole, empty); p->setFlags(p->flags() | Qt::ItemIsEditable); p->setText(1, (*it).id()); p->setText(2, (*it).tradingSymbol()); } ui->m_currencyList->sortItems(0, Qt::AscendingOrder); } void KAvailableCurrencyDlg::slotItemSelectionChanged() { ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!ui->m_currencyList->selectedItems().isEmpty()); } diff --git a/kmymoney/dialogs/kavailablecurrencydlg.h b/kmymoney/dialogs/kavailablecurrencydlg.h index c30bba70d..8d060fca2 100644 --- a/kmymoney/dialogs/kavailablecurrencydlg.h +++ b/kmymoney/dialogs/kavailablecurrencydlg.h @@ -1,54 +1,54 @@ /*************************************************************************** kavailablecurrencydlg.h - description ------------------- begin : Sat Apr 01 2017 copyright : (C) 2017 Ł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. * * * ***************************************************************************/ -#ifndef KAVAILABLECURRENCYEDITDLG_H -#define KAVAILABLECURRENCYEDITDLG_H +#ifndef KAVAILABLECURRENCYDLG_H +#define KAVAILABLECURRENCYDLG_H // ---------------------------------------------------------------------------- // QT Includes // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes namespace Ui { class KAvailableCurrencyDlg; } class KTreeWidgetSearchLineWidget; class KAvailableCurrencyDlg : public QDialog { Q_OBJECT public: - KAvailableCurrencyDlg(QWidget *parent = 0); + KAvailableCurrencyDlg(QWidget *parent = nullptr); ~KAvailableCurrencyDlg(); Ui::KAvailableCurrencyDlg* ui; protected slots: void slotLoadCurrencies(); void slotItemSelectionChanged(); private: KTreeWidgetSearchLineWidget* m_searchWidget; }; #endif diff --git a/kmymoney/dialogs/kbackupdlg.cpp b/kmymoney/dialogs/kbackupdlg.cpp index 237bba517..589c0dc10 100644 --- a/kmymoney/dialogs/kbackupdlg.cpp +++ b/kmymoney/dialogs/kbackupdlg.cpp @@ -1,95 +1,105 @@ /*************************************************************************** kbackupdialog.cpp - description ------------------- begin : Mon Jun 4 2001 copyright : (C) 2001 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kbackupdlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include -#include #include #include // ---------------------------------------------------------------------------- // Project Includes + +#include "ui_kbackupdlg.h" + #include "icons/icons.h" using namespace Icons; -KBackupDlg::KBackupDlg(QWidget* parent) - : kbackupdlgdecl(parent) +KBackupDlg::KBackupDlg(QWidget* parent) : + QDialog(parent), + ui(new Ui::KBackupDlg) { + ui->setupUi(this); readConfig(); - KGuiItem chooseButtenItem(i18n("C&hoose..."), - QIcon::fromTheme(g_Icons[Icon::Folder]), - i18n("Select mount point"), - i18n("Use this to browse to the mount point.")); - KGuiItem::assign(chooseButton, chooseButtenItem); + ui->chooseButton->setIcon(QIcon::fromTheme(g_Icons[Icon::Folder])); - connect(chooseButton, SIGNAL(clicked()), this, SLOT(chooseButtonClicked())); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(ui->chooseButton, &QAbstractButton::clicked, this, &KBackupDlg::chooseButtonClicked); } KBackupDlg::~KBackupDlg() { writeConfig(); + delete ui; +} + +QString KBackupDlg::mountPoint() const +{ + return ui->txtMountPoint->text(); +} + +bool KBackupDlg::mountCheckBox() const +{ + return ui->mountCheckBox; } void KBackupDlg::chooseButtonClicked() { - QUrl newDir = QFileDialog::getExistingDirectoryUrl(this, QString(), QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation))); + auto newDir = QFileDialog::getExistingDirectoryUrl(this, QString(), QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation))); if (!newDir.path().isEmpty()) - txtMountPoint->setText(newDir.path()); + ui->txtMountPoint->setText(newDir.path()); } void KBackupDlg::readConfig() { QString backupDefaultLocation; #ifdef Q_OS_WIN backupDefaultLocation = QDir::toNativeSeparators(QDir::homePath() + "/kmymoney/backup"); #else backupDefaultLocation = "/mnt/floppy"; #endif KSharedConfigPtr config = KSharedConfig::openConfig(); KConfigGroup grp = config->group("Last Use Settings"); - mountCheckBox->setChecked(grp.readEntry("KBackupDlg_mountDevice", false)); - txtMountPoint->setText(grp.readEntry("KBackupDlg_BackupMountPoint", backupDefaultLocation)); + ui->mountCheckBox->setChecked(grp.readEntry("KBackupDlg_mountDevice", false)); + ui->txtMountPoint->setText(grp.readEntry("KBackupDlg_BackupMountPoint", backupDefaultLocation)); } void KBackupDlg::writeConfig() { KSharedConfigPtr config = KSharedConfig::openConfig(); KConfigGroup grp = config->group("Last Use Settings"); - grp.writeEntry("KBackupDlg_mountDevice", mountCheckBox->isChecked()); - grp.writeEntry("KBackupDlg_BackupMountPoint", txtMountPoint->text()); + grp.writeEntry("KBackupDlg_mountDevice", ui->mountCheckBox->isChecked()); + grp.writeEntry("KBackupDlg_BackupMountPoint", ui->txtMountPoint->text()); config->sync(); } diff --git a/kmymoney/dialogs/kbackupdlg.h b/kmymoney/dialogs/kbackupdlg.h index 7600cd0ac..c0fd9b02f 100644 --- a/kmymoney/dialogs/kbackupdlg.h +++ b/kmymoney/dialogs/kbackupdlg.h @@ -1,54 +1,53 @@ /*************************************************************************** kbackupdialog.h - description ------------------- begin : Mon Jun 4 2001 copyright : (C) 2001 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KBACKUPDLG_H #define KBACKUPDLG_H #include -#include "ui_kbackupdlgdecl.h" + +namespace Ui { class KBackupDlg; } /** *@author Michael Edwardes */ - -class kbackupdlgdecl : public QDialog, public Ui::kbackupdlgdecl +class KBackupDlg : public QDialog { + Q_OBJECT + Q_DISABLE_COPY(KBackupDlg) + public: - kbackupdlgdecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; + explicit KBackupDlg(QWidget* parent = nullptr); + ~KBackupDlg(); -class KBackupDlg : public kbackupdlgdecl -{ - Q_OBJECT -private: - void readConfig(); - void writeConfig(); + QString mountPoint() const; + bool mountCheckBox() const; protected slots: void chooseButtonClicked(); -public: - KBackupDlg(QWidget* parent); - ~KBackupDlg(); +private: + Ui::KBackupDlg *ui; + void readConfig(); + void writeConfig(); }; #endif // KBACKUPDLG_H diff --git a/kmymoney/dialogs/kbackupdlgdecl.ui b/kmymoney/dialogs/kbackupdlg.ui similarity index 83% rename from kmymoney/dialogs/kbackupdlgdecl.ui rename to kmymoney/dialogs/kbackupdlg.ui index 493b357b9..706691fd4 100644 --- a/kmymoney/dialogs/kbackupdlgdecl.ui +++ b/kmymoney/dialogs/kbackupdlg.ui @@ -1,183 +1,222 @@ - kbackupdlgdecl - + KBackupDlg + 0 0 641 301 Backup 6 11 11 11 11 6 0 0 0 0 Use this dialog to backup your data. Please make sure you have a disk inserted and that the drive is ready. Then choose the mount point from either the Choose button or by entering the path in the available box. Click OK to perform the backup. If your system does not use an automounter, make sure you mark the checkbox below to "mount this directory before backing up." Qt::AlignTop true QFrame::HLine QFrame::Raised Device options 6 11 11 11 11 6 0 0 0 0 Mount Point: false + + Select mount point + + + Use this to browse to the mount point. + C&hoose... Mount this directory before backing up. Qt::Vertical QSizePolicy::Expanding 0 24 QDialogButtonBox::Cancel|QDialogButtonBox::Ok KLineEdit QLineEdit
klineedit.h
- + + + buttonBox + accepted() + KBackupDlg + accept() + + + 320 + 272 + + + 320 + 150 + + + + + buttonBox + rejected() + KBackupDlg + reject() + + + 320 + 272 + + + 320 + 150 + + + +
diff --git a/kmymoney/dialogs/kbalancechartdlg.cpp b/kmymoney/dialogs/kbalancechartdlg.cpp index bf923ca3a..30c9845a2 100644 --- a/kmymoney/dialogs/kbalancechartdlg.cpp +++ b/kmymoney/dialogs/kbalancechartdlg.cpp @@ -1,162 +1,163 @@ /*************************************************************************** kbalancechartdlg - description ------------------- begin : Mon Nov 26 2007 copyright : (C) 2007 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kbalancechartdlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include #include // ---------------------------------------------------------------------------- // Project Includes #include "mymoneyreport.h" #include "pivottable.h" #include "kreportchartview.h" using namespace reports; KBalanceChartDlg::KBalanceChartDlg(const MyMoneyAccount& account, QWidget* parent) : QDialog(parent) { setWindowTitle(i18n("Balance of %1", account.name())); setSizeGripEnabled(true); setModal(true); // restore the last used dialog size winId(); // needs to be called to create the QWindow KConfigGroup grp = KSharedConfig::openConfig()->group("KBalanceChartDlg"); if (grp.isValid()) { KWindowConfig::restoreWindowSize(windowHandle(), grp); } // let the minimum size be 700x500 resize(QSize(700, 500).expandedTo(windowHandle() ? windowHandle()->size() : QSize())); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); //draw the chart and add it to the main layout KReportChartView* chartWidget = drawChart(account); mainLayout->addWidget(chartWidget); // add the buttons QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); mainLayout->addWidget(buttonBox); } KBalanceChartDlg::~KBalanceChartDlg() { // store the last used dialog size KConfigGroup grp = KSharedConfig::openConfig()->group("KBalanceChartDlg"); if (grp.isValid()) { KWindowConfig::saveWindowSize(windowHandle(), grp); } } KReportChartView* KBalanceChartDlg::drawChart(const MyMoneyAccount& account) { MyMoneyReport reportCfg = MyMoneyReport( MyMoneyReport::eAssetLiability, MyMoneyReport::eMonths, eMyMoney::TransactionFilter::Date::Last3ToNext3Months, MyMoneyReport::eDetailTotal, i18n("%1 Balance History", account.name()), i18n("Generated Report") ); reportCfg.setChartByDefault(true); reportCfg.setChartCHGridLines(false); reportCfg.setChartSVGridLines(false); reportCfg.setChartDataLabels(false); reportCfg.setChartType(MyMoneyReport::eChartLine); reportCfg.setIncludingForecast(true); reportCfg.setIncludingBudgetActuals(true); if (account.accountType() == eMyMoney::Account::Investment) { foreach (const auto accountID, account.accountList()) reportCfg.addAccount(accountID); } else reportCfg.addAccount(account.id()); reportCfg.setColumnsAreDays(true); reportCfg.setConvertCurrency(false); reportCfg.setMixedTime(true); reports::PivotTable table(reportCfg); reports::KReportChartView* chartWidget = new reports::KReportChartView(this); table.drawChart(*chartWidget); // add another row for limit bool needRow = false; bool haveMinBalance = false; bool haveMaxCredit = false; MyMoneyMoney minBalance, maxCredit; MyMoneyMoney factor(1, 1); if (account.accountGroup() == eMyMoney::Account::Asset) factor = -factor; if (!account.value("maxCreditEarly").isEmpty()) { needRow = true; haveMaxCredit = true; maxCredit = MyMoneyMoney(account.value("maxCreditEarly")) * factor; } if (!account.value("maxCreditAbsolute").isEmpty()) { needRow = true; haveMaxCredit = true; maxCredit = MyMoneyMoney(account.value("maxCreditAbsolute")) * factor; } if (!account.value("minBalanceEarly").isEmpty()) { needRow = true; haveMinBalance = true; minBalance = MyMoneyMoney(account.value("minBalanceEarly")); } if (!account.value("minBalanceAbsolute").isEmpty()) { needRow = true; haveMinBalance = true; minBalance = MyMoneyMoney(account.value("minBalanceAbsolute")); } if (needRow) { if (haveMinBalance) { chartWidget->drawLimitLine(minBalance.toDouble()); } if (haveMaxCredit) { chartWidget->drawLimitLine(maxCredit.toDouble()); } } // always draw the y axis zero value line // TODO: port to KF5 - this crashes KChart //chartWidget->drawLimitLine(0); //remove the legend chartWidget->removeLegend(); return chartWidget; } diff --git a/kmymoney/dialogs/kbalancechartdlg.h b/kmymoney/dialogs/kbalancechartdlg.h index 5954a6b3d..d76c6d046 100644 --- a/kmymoney/dialogs/kbalancechartdlg.h +++ b/kmymoney/dialogs/kbalancechartdlg.h @@ -1,56 +1,57 @@ /*************************************************************************** kbalancechartdlg - description ------------------- begin : Mon Nov 26 2007 copyright : (C) 2007 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KBALANCECHARTDLG_H #define KBALANCECHARTDLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes namespace reports { class KReportChartView; } class MyMoneyAccount; /** * @author Thomas Baumgart * This dialog displays a chart with the account balance for the last 90 days. * It also draws the account limit if the account has any. */ class KBalanceChartDlg : public QDialog { Q_OBJECT public: - explicit KBalanceChartDlg(const MyMoneyAccount& account, QWidget* parent = 0); + explicit KBalanceChartDlg(const MyMoneyAccount& account, QWidget* parent = nullptr); ~KBalanceChartDlg(); protected: /** * Draw the chart and calculate and draw the account limits if any */ reports::KReportChartView* drawChart(const MyMoneyAccount& account); }; #endif diff --git a/kmymoney/dialogs/kbalancewarning.cpp b/kmymoney/dialogs/kbalancewarning.cpp index bdd1b6cde..7fd51e002 100644 --- a/kmymoney/dialogs/kbalancewarning.cpp +++ b/kmymoney/dialogs/kbalancewarning.cpp @@ -1,65 +1,66 @@ /*************************************************************************** kbalancewarning.cpp ------------------- begin : Mon Feb 9 2009 copyright : (C) 2009 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kbalancewarning.h" // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes #include "mymoneyaccount.h" class KBalanceWarning::Private { public: QString dontShowAgain() const { return "BalanceWarning"; } QMap m_deselectedAccounts; }; KBalanceWarning::KBalanceWarning(QObject* parent) : QObject(parent), d(new Private) { KMessageBox::enableMessage(d->dontShowAgain()); } KBalanceWarning::~KBalanceWarning() { delete d; } void KBalanceWarning::slotShowMessage(QWidget* parent, const MyMoneyAccount& account, const QString& msg) { if (d->m_deselectedAccounts.find(account.id()) == d->m_deselectedAccounts.end()) { KMessageBox::information(parent, msg, QString(), d->dontShowAgain()); if (!KMessageBox::shouldBeShownContinue(d->dontShowAgain())) { d->m_deselectedAccounts[account.id()] = true; KMessageBox::enableMessage(d->dontShowAgain()); } } } diff --git a/kmymoney/dialogs/kbalancewarning.h b/kmymoney/dialogs/kbalancewarning.h index 71838446b..64f47483b 100644 --- a/kmymoney/dialogs/kbalancewarning.h +++ b/kmymoney/dialogs/kbalancewarning.h @@ -1,50 +1,51 @@ /*************************************************************************** kbalancewarning.h ------------------- begin : Mon Feb 9 2009 copyright : (C) 2009 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KBALANCEWARNING_H #define KBALANCEWARNING_H // ---------------------------------------------------------------------------- // QT Includes #include class QString; class QWidget; // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes class MyMoneyAccount; class KBalanceWarning : public QObject { Q_OBJECT public: explicit KBalanceWarning(QObject* parent); virtual ~KBalanceWarning(); public slots: void slotShowMessage(QWidget* parent, const MyMoneyAccount& account, const QString& msg); private: class Private; Private* d; }; #endif diff --git a/kmymoney/dialogs/kcategoryreassigndlg.cpp b/kmymoney/dialogs/kcategoryreassigndlg.cpp index 4268826fe..cc24712ea 100644 --- a/kmymoney/dialogs/kcategoryreassigndlg.cpp +++ b/kmymoney/dialogs/kcategoryreassigndlg.cpp @@ -1,102 +1,107 @@ /*************************************************************************** kcategoryreassigndlg.cpp ------------------- copyright : (C) 2007 by Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kcategoryreassigndlg.h" // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kcategoryreassigndlg.h" + #include "mymoneyfile.h" #include "mymoneyaccount.h" #include "kmymoneycategory.h" #include "kmymoneyaccountselector.h" KCategoryReassignDlg::KCategoryReassignDlg(QWidget* parent) : - KCategoryReassignDlgDecl(parent) + QDialog(parent), + ui(new Ui::KCategoryReassignDlg) { - kMandatoryFieldGroup* mandatory = new kMandatoryFieldGroup(this); - mandatory->add(m_category); - mandatory->setOkButton(buttonBox->button(QDialogButtonBox::Ok)); + ui->setupUi(this); + auto mandatory = new kMandatoryFieldGroup(this); + mandatory->add(ui->m_category); + mandatory->setOkButton(ui->buttonBox->button(QDialogButtonBox::Ok)); } KCategoryReassignDlg::~KCategoryReassignDlg() { + delete ui; } QString KCategoryReassignDlg::show(const MyMoneyAccount& category) { if (category.id().isEmpty()) return QString(); // no payee available? nothing can be selected... AccountSet set; set.addAccountGroup(eMyMoney::Account::Income); set.addAccountGroup(eMyMoney::Account::Expense); - set.load(m_category->selector()); + set.load(ui->m_category->selector()); // remove the category we are about to delete - m_category->selector()->removeItem(category.id()); + ui->m_category->selector()->removeItem(category.id()); // make sure the available categories have the same currency QStringList list; QStringList::const_iterator it_a; - m_category->selector()->itemList(list); + ui->m_category->selector()->itemList(list); for (it_a = list.constBegin(); it_a != list.constEnd(); ++it_a) { MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a); if (acc.currencyId() != category.currencyId()) - m_category->selector()->removeItem(*it_a); + ui->m_category->selector()->removeItem(*it_a); } // reload the list - m_category->selector()->itemList(list); + ui->m_category->selector()->itemList(list); // if there is no category for reassignment left, we bail out if (list.isEmpty()) { KMessageBox::sorry(this, QString("") + i18n("At least one transaction/schedule still references the category %1. However, at least one category with the same currency must exist so that the transactions/schedules can be reassigned.", category.name()) + QString("")); return QString(); } // execute dialog and if aborted, return empty string if (this->exec() == QDialog::Rejected) return QString(); // otherwise return index of selected payee - return m_category->selectedItem(); + return ui->m_category->selectedItem(); } void KCategoryReassignDlg::accept() { // force update of payeeCombo - buttonBox->button(QDialogButtonBox::Ok)->setFocus(); + ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); - if (m_category->selectedItem().isEmpty()) { + if (ui->m_category->selectedItem().isEmpty()) KMessageBox::information(this, i18n("This dialog does not allow new categories to be created. Please pick a category from the list."), i18n("Category creation")); - } else { - KCategoryReassignDlgDecl::accept(); - } + else + QDialog::accept(); } diff --git a/kmymoney/dialogs/kcategoryreassigndlg.h b/kmymoney/dialogs/kcategoryreassigndlg.h index eef17e8d9..fe116c440 100644 --- a/kmymoney/dialogs/kcategoryreassigndlg.h +++ b/kmymoney/dialogs/kcategoryreassigndlg.h @@ -1,72 +1,68 @@ /*************************************************************************** kcategoryreassigndlg.cpp ------------------- copyright : (C) 2007 by Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KCATEGORYREASSIGNDLG_H #define KCATEGORYREASSIGNDLG_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_kcategoryreassigndlgdecl.h" +class MyMoneyAccount; +namespace Ui { class KCategoryReassignDlg; } /** * Implementation of the dialog that lets the user select a payee in order * to re-assign transactions (for instance, if payees are deleted). */ -class KCategoryReassignDlgDecl : public QDialog, public Ui::KCategoryReassignDlgDecl -{ -public: - KCategoryReassignDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; - -class MyMoneyAccount; -class KCategoryReassignDlg : public KCategoryReassignDlgDecl +class KCategoryReassignDlg : public QDialog { Q_OBJECT -public: - /** Default constructor */ - KCategoryReassignDlg(QWidget* parent = 0); + Q_DISABLE_COPY(KCategoryReassignDlg) - /** Destructor */ +public: + explicit KCategoryReassignDlg(QWidget* parent = nullptr); ~KCategoryReassignDlg(); /** * This function sets up the dialog, lets the user select a category and returns * the id of the selected category in the list of all known income and expense accounts. * * @param category reference to MyMoneyAccount object of the category to be deleted * * @return Returns the id of the selected category in the list or QString() if * the dialog was aborted. QString() is also returned if the @a category * does not have an id. */ QString show(const MyMoneyAccount& category); protected: void accept(); +private: + Ui::KCategoryReassignDlg *ui; }; #endif // KCATEGORYREASSIGNDLG_H diff --git a/kmymoney/dialogs/kcategoryreassigndlgdecl.ui b/kmymoney/dialogs/kcategoryreassigndlg.ui similarity index 94% rename from kmymoney/dialogs/kcategoryreassigndlgdecl.ui rename to kmymoney/dialogs/kcategoryreassigndlg.ui index 1ffa9ba34..fa447fbf7 100644 --- a/kmymoney/dialogs/kcategoryreassigndlgdecl.ui +++ b/kmymoney/dialogs/kcategoryreassigndlg.ui @@ -1,154 +1,154 @@ - KCategoryReassignDlgDecl - + KCategoryReassignDlg + 0 0 392 308 Reassign categories false true 300 0 The transactions, schedules and budgets associated with the selected category need to be re-assigned to a different category before the selected category can be deleted. Please select a category from the list below. Qt::AlignJustify|Qt::AlignTop true Qt::Vertical QSizePolicy::Fixed 20 16 Available categories: false Qt::Vertical QSizePolicy::Expanding 20 16 QFrame::HLine QFrame::Sunken QDialogButtonBox::Cancel|QDialogButtonBox::Ok KComboBox QComboBox
kcombobox.h
KMyMoneyCategory KComboBox
kmymoneycategory.h
buttonBox accepted() - KCategoryReassignDlgDecl + KCategoryReassignDlg accept() 260 288 92 304 buttonBox rejected() - KCategoryReassignDlgDecl + KCategoryReassignDlg reject() 352 288 322 304
diff --git a/kmymoney/dialogs/kchooseimportexportdlg.cpp b/kmymoney/dialogs/kchooseimportexportdlg.cpp index af48240ca..0a6eadaf2 100644 --- a/kmymoney/dialogs/kchooseimportexportdlg.cpp +++ b/kmymoney/dialogs/kchooseimportexportdlg.cpp @@ -1,115 +1,133 @@ /*************************************************************************** kchooseimportexportdlg.cpp - description ------------------- begin : Thu Jul 12 2001 copyright : (C) 2000-2001 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kchooseimportexportdlg.h" // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include #include // ---------------------------------------------------------------------------- // Project Includes -#include "ui_kchooseimportexportdlgdecl.h" +#include "ui_kchooseimportexportdlg.h" -struct KChooseImportExportDlg::Private { - Ui::KChooseImportExportDlgDecl ui; +class KChooseImportExportDlgPrivate +{ + Q_DISABLE_COPY(KChooseImportExportDlgPrivate) + +public: + KChooseImportExportDlgPrivate() : + ui(new Ui::KChooseImportExportDlg) + { + } + + ~KChooseImportExportDlgPrivate() + { + delete ui; + } + + void readConfig() + { + auto config = KSharedConfig::openConfig(); + auto grp = config->group("Last Use Settings"); + m_lastType = grp.readEntry("KChooseImportExportDlg_LastType"); + } + + void writeConfig() const + { + auto config = KSharedConfig::openConfig(); + auto grp = config->group("Last Use Settings"); + grp.writeEntry("KChooseImportExportDlg_LastType", ui->typeCombo->currentText()); + config->sync(); + } + + Ui::KChooseImportExportDlg *ui; + QString m_lastType; }; -KChooseImportExportDlg::KChooseImportExportDlg(int type, QWidget *parent) - : QDialog(parent), d(new Private) -{ - d->ui.setupUi(this); - QString filename; +KChooseImportExportDlg::KChooseImportExportDlg(int type, QWidget *parent) : + QDialog(parent), + d_ptr(new KChooseImportExportDlgPrivate) +{ + Q_D(KChooseImportExportDlg); + d->ui->setupUi(this); setModal(true); if (type == 0) { // import - d->ui.topLabel->setText(i18n("Please choose the type of import you wish to perform. A simple explanation\n" + d->ui->topLabel->setText(i18n("Please choose the type of import you wish to perform. A simple explanation\n" "of the import type is available at the bottom of the screen and is updated when\n" "you select an item from the choice box." "\n\nOnce you have chosen an import type please press the OK button.")); - d->ui.promptLabel->setText(i18n("Choose import type:")); + d->ui->promptLabel->setText(i18n("Choose import type:")); setWindowTitle(i18n("Choose Import Type Dialog")); } else { // export - d->ui.topLabel->setText(i18n("Please choose the type of export you wish to perform. A simple explanation\n" + d->ui->topLabel->setText(i18n("Please choose the type of export you wish to perform. A simple explanation\n" "of the export type is available at the bottom of the screen and is updated when\n" "you select an item from the choice box." "\n\nOnce you have chosen an export type please press the OK button.")); - d->ui.promptLabel->setText(i18n("Choose export type:")); + d->ui->promptLabel->setText(i18n("Choose export type:")); setWindowTitle(i18n("Choose Export Type Dialog")); } - readConfig(); - slotTypeActivated(m_lastType); - d->ui.typeCombo->setCurrentItem(((m_lastType == "QIF") ? i18n("QIF") : i18n("CSV")), false); + d->readConfig(); + slotTypeActivated(d->m_lastType); + d->ui->typeCombo->setCurrentItem(((d->m_lastType == "QIF") ? i18n("QIF") : i18n("CSV")), false); - connect(d->ui.typeCombo, SIGNAL(activated(QString)), this, SLOT(slotTypeActivated(QString))); - connect(d->ui.buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(d->ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(d->ui->typeCombo, static_cast(&QComboBox::activated), this, &KChooseImportExportDlg::slotTypeActivated); } KChooseImportExportDlg::~KChooseImportExportDlg() { - writeConfig(); + Q_D(KChooseImportExportDlg); + d->writeConfig(); delete d; } void KChooseImportExportDlg::slotTypeActivated(const QString& text) { + Q_D(KChooseImportExportDlg); if (text == "QIF") { - d->ui.descriptionLabel->setText(i18n("QIF files are created by the popular accounting program Quicken.\n" + d->ui->descriptionLabel->setText(i18n("QIF files are created by the popular accounting program Quicken.\n" "Another dialog will appear, if you choose this type, asking for further\n" "information relevant to the Quicken format.")); } else { - d->ui.descriptionLabel->setText(i18n("The CSV type uses a comma delimited text file that can be used by\n" + d->ui->descriptionLabel->setText(i18n("The CSV type uses a comma delimited text file that can be used by\n" "most popular spreadsheet programs available for Linux and other operating\n" "systems.")); } } -QString KChooseImportExportDlg::importExportType() -{ - return d->ui.typeCombo->currentText(); -} - -void KChooseImportExportDlg::readConfig() -{ - KSharedConfigPtr config = KSharedConfig::openConfig(); - KConfigGroup grp = config->group("Last Use Settings"); - m_lastType = grp.readEntry("KChooseImportExportDlg_LastType"); -} - -void KChooseImportExportDlg::writeConfig() +QString KChooseImportExportDlg::importExportType() const { - KSharedConfigPtr config = KSharedConfig::openConfig(); - KConfigGroup grp = config->group("Last Use Settings"); - grp.writeEntry("KChooseImportExportDlg_LastType", d->ui.typeCombo->currentText()); - config->sync(); + Q_D(const KChooseImportExportDlg); + return d->ui->typeCombo->currentText(); } diff --git a/kmymoney/dialogs/kchooseimportexportdlg.h b/kmymoney/dialogs/kchooseimportexportdlg.h index 675263efd..d72f6e99e 100644 --- a/kmymoney/dialogs/kchooseimportexportdlg.h +++ b/kmymoney/dialogs/kchooseimportexportdlg.h @@ -1,61 +1,59 @@ /*************************************************************************** kchooseimportexportdlg.h - description ------------------- begin : Thu Jul 12 2001 copyright : (C) 2000-2001 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KCHOOSEIMPORTEXPORTDLG_H #define KCHOOSEIMPORTEXPORTDLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes /** *@author Michael Edwardes */ + +class KChooseImportExportDlgPrivate; class KChooseImportExportDlg : public QDialog { Q_OBJECT -private: - void readConfig(); - void writeConfig(); - QString m_lastType; - -protected slots: - void slotTypeActivated(const QString& text); + Q_DISABLE_COPY(KChooseImportExportDlg) public: - explicit KChooseImportExportDlg(int type, QWidget *parent = 0); + explicit KChooseImportExportDlg(int type, QWidget *parent = nullptr); ~KChooseImportExportDlg(); - QString importExportType(); + QString importExportType() const; + +protected slots: + void slotTypeActivated(const QString& text); private: - /// \internal d-pointer class. - struct Private; - /// \internal d-pointer instance. - Private* const d; + KChooseImportExportDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KChooseImportExportDlg) }; #endif diff --git a/kmymoney/dialogs/kchooseimportexportdlgdecl.ui b/kmymoney/dialogs/kchooseimportexportdlg.ui similarity index 83% rename from kmymoney/dialogs/kchooseimportexportdlgdecl.ui rename to kmymoney/dialogs/kchooseimportexportdlg.ui index 0a2b26e36..006326ac8 100644 --- a/kmymoney/dialogs/kchooseimportexportdlgdecl.ui +++ b/kmymoney/dialogs/kchooseimportexportdlg.ui @@ -1,177 +1,210 @@ - KChooseImportExportDlgDecl - + KChooseImportExportDlg + 0 0 530 - 276 + 309 Choose Import Type Dialog 6 11 11 11 11 6 0 0 0 0 Please choose the type of import you wish to perform. A simple explanation of the import type is available at the bottom of the screen and is updated when you select an item from the choice box. Once you have chosen an import type please press the OK button. false QFrame::Raised 6 0 0 0 0 Qt::Horizontal QSizePolicy::Expanding 20 20 Choose import type: false 100 0 QIF CSV 0 0 410 100 Some description false QDialogButtonBox::Cancel|QDialogButtonBox::Ok KComboBox QComboBox
kcombobox.h
- + + + buttonBox + accepted() + KChooseImportExportDlg + accept() + + + 264 + 280 + + + 264 + 154 + + + + + buttonBox + rejected() + KChooseImportExportDlg + reject() + + + 264 + 280 + + + 264 + 154 + + + +
diff --git a/kmymoney/dialogs/kconfirmmanualenterdlg.cpp b/kmymoney/dialogs/kconfirmmanualenterdlg.cpp index 6b37f71f6..48106b7db 100644 --- a/kmymoney/dialogs/kconfirmmanualenterdlg.cpp +++ b/kmymoney/dialogs/kconfirmmanualenterdlg.cpp @@ -1,193 +1,192 @@ /*************************************************************************** kconfirmmanualenterdlg.cpp ------------------- begin : Mon Apr 9 2007 copyright : (C) 2007 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kconfirmmanualenterdlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kconfirmmanualenterdlg.h" + #include "mymoneymoney.h" #include "mymoneyfile.h" #include "mymoneyaccount.h" #include "mymoneysecurity.h" #include "mymoneypayee.h" #include "mymoneysplit.h" #include "mymoneyschedule.h" #include "mymoneyexception.h" #include "kmymoneyutils.h" #include "mymoneytransaction.h" -#include "ui_kconfirmmanualenterdlgdecl.h" - -struct KConfirmManualEnterDlg::Private { - Ui::KConfirmManualEnterDlgDecl ui; -}; KConfirmManualEnterDlg::KConfirmManualEnterDlg(const MyMoneySchedule& schedule, QWidget* parent) : - QDialog(parent), d(new Private) + QDialog(parent), + ui(new Ui::KConfirmManualEnterDlg) { - d->ui.setupUi(this); - d->ui.buttonGroup1->setId(d->ui.m_discardRadio, 0); - d->ui.buttonGroup1->setId(d->ui.m_onceRadio, 1); - d->ui.buttonGroup1->setId(d->ui.m_setRadio, 2); + ui->setupUi(this); + ui->buttonGroup1->setId(ui->m_discardRadio, 0); + ui->buttonGroup1->setId(ui->m_onceRadio, 1); + ui->buttonGroup1->setId(ui->m_setRadio, 2); - d->ui.m_onceRadio->setChecked(true); + ui->m_onceRadio->setChecked(true); if (schedule.type() == eMyMoney::Schedule::Type::LoanPayment) { - d->ui.m_setRadio->setEnabled(false); - d->ui.m_discardRadio->setEnabled(false); + ui->m_setRadio->setEnabled(false); + ui->m_discardRadio->setEnabled(false); } } KConfirmManualEnterDlg::~KConfirmManualEnterDlg() { - delete d; + delete ui; } void KConfirmManualEnterDlg::loadTransactions(const MyMoneyTransaction& to, const MyMoneyTransaction& tn) { QString messageDetail(""); - MyMoneyFile* file = MyMoneyFile::instance(); + auto file = MyMoneyFile::instance(); int noItemsChanged = 0; try { if (to.splits().isEmpty()) throw MYMONEYEXCEPTION(i18n("Transaction %1 has no splits", to.id())); if (tn.splits().isEmpty()) throw MYMONEYEXCEPTION(i18n("Transaction %1 has no splits", tn.id())); QString po, pn; if (!to.splits().front().payeeId().isEmpty()) po = file->payee(to.splits().front().payeeId()).name(); if (!tn.splits().front().payeeId().isEmpty()) pn = file->payee(tn.splits().front().payeeId()).name(); if (po != pn) { noItemsChanged++; messageDetail += i18n("

Payee changed.
   Old: %1, New: %2

", po, pn); } if (to.splits().front().accountId() != tn.splits().front().accountId()) { noItemsChanged++; messageDetail += i18n("

Account changed.
   Old: %1, New: %2

" , file->account(to.splits().front().accountId()).name() , file->account(tn.splits().front().accountId()).name()); } if (file->isTransfer(to) && file->isTransfer(tn)) { if (to.splits()[1].accountId() != tn.splits()[1].accountId()) { noItemsChanged++; messageDetail += i18n("

Transfer account changed.
   Old: %1, New: %2

" , file->account(to.splits()[1].accountId()).name() , file->account(tn.splits()[1].accountId()).name()); } } else { QString co, cn; switch (to.splitCount()) { default: co = i18nc("Split transaction (category replacement)", "Split transaction"); break; case 2: co = file->accountToCategory(to.splits()[1].accountId()); case 1: break; } switch (tn.splitCount()) { default: cn = i18nc("Split transaction (category replacement)", "Split transaction"); break; case 2: cn = file->accountToCategory(tn.splits()[1].accountId()); case 1: break; } if (co != cn) { noItemsChanged++; messageDetail += i18n("

Category changed.
   Old: %1, New: %2

", co, cn); } } QString mo, mn; mo = to.splits().front().memo(); mn = tn.splits().front().memo(); if (mo.isEmpty()) mo = QString("") + i18nc("Empty memo", "empty") + QString(""); if (mn.isEmpty()) mn = QString("") + i18nc("Empty memo", "empty") + QString(""); if (mo != mn) { noItemsChanged++; messageDetail += i18n("

Memo changed.
   Old: %1, New: %2

", mo, mn); } QString no, nn; no = to.splits().front().number(); nn = tn.splits().front().number(); if (no.isEmpty()) no = QString("") + i18nc("No number", "empty") + QString(""); if (nn.isEmpty()) nn = QString("") + i18nc("No number", "empty") + QString(""); if (no != nn) { noItemsChanged++; messageDetail += i18n("

Number changed.
   Old: %1, New: %2

", no, nn); } const MyMoneySecurity& sec = MyMoneyFile::instance()->security(to.commodity()); MyMoneyMoney ao, an; ao = to.splits().front().value(); an = tn.splits().front().value(); if (ao != an) { noItemsChanged++; messageDetail += i18n("

Amount changed.
   Old: %1, New: %2

", ao.formatMoney(sec.smallestAccountFraction()), an.formatMoney(sec.smallestAccountFraction())); } eMyMoney::Split::State fo, fn; fo = to.splits().front().reconcileFlag(); fn = tn.splits().front().reconcileFlag(); if (fo != fn) { noItemsChanged++; messageDetail += i18n("

Reconciliation flag changed.
   Old: %1, New: %2

", KMyMoneyUtils::reconcileStateToString(fo, true), KMyMoneyUtils::reconcileStateToString(fn, true)); } } catch (const MyMoneyException &e) { KMessageBox::error(this, i18n("Fatal error in determining data: %1", e.what())); } messageDetail += "
"; - d->ui.m_details->setText(messageDetail); + ui->m_details->setText(messageDetail); return; } KConfirmManualEnterDlg::Action KConfirmManualEnterDlg::action() const { - if (d->ui.m_discardRadio->isChecked()) + if (ui->m_discardRadio->isChecked()) return UseOriginal; - if (d->ui.m_setRadio->isChecked()) + if (ui->m_setRadio->isChecked()) return ModifyAlways; return ModifyOnce; } diff --git a/kmymoney/dialogs/kconfirmmanualenterdlg.h b/kmymoney/dialogs/kconfirmmanualenterdlg.h index e16289c2c..12c5b1996 100644 --- a/kmymoney/dialogs/kconfirmmanualenterdlg.h +++ b/kmymoney/dialogs/kconfirmmanualenterdlg.h @@ -1,67 +1,68 @@ /*************************************************************************** kconfirmmanualenterdlg.h ------------------- begin : Mon Apr 9 2007 copyright : (C) 2007 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KCONFIRMMANUALENTERDLG_H #define KCONFIRMMANUALENTERDLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes class MyMoneySchedule; class MyMoneyTransaction; +namespace Ui { class KConfirmManualEnterDlg; } + class KConfirmManualEnterDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KConfirmManualEnterDlg) public: - explicit KConfirmManualEnterDlg(const MyMoneySchedule& schedule, QWidget* parent = 0); + explicit KConfirmManualEnterDlg(const MyMoneySchedule& schedule, QWidget* parent = nullptr); ~KConfirmManualEnterDlg(); typedef enum { UseOriginal = 0, ModifyOnce, ModifyAlways } Action; /** * setup the dialog for the difference between the original transaction * @a to and the transaction to be entered @a tn. */ void loadTransactions(const MyMoneyTransaction& to, const MyMoneyTransaction& tn); /** * Returns information about what to do with the transaction */ Action action() const; private: - /// \internal d-pointer class. - struct Private; - /// \internal d-pointer instance. - Private* const d; + Ui::KConfirmManualEnterDlg *ui; }; #endif // KCONFIRMMANUALENTERDLG_H diff --git a/kmymoney/dialogs/kconfirmmanualenterdlgdecl.ui b/kmymoney/dialogs/kconfirmmanualenterdlg.ui similarity index 94% rename from kmymoney/dialogs/kconfirmmanualenterdlgdecl.ui rename to kmymoney/dialogs/kconfirmmanualenterdlg.ui index 86d211d4e..685326e1d 100644 --- a/kmymoney/dialogs/kconfirmmanualenterdlgdecl.ui +++ b/kmymoney/dialogs/kconfirmmanualenterdlg.ui @@ -1,155 +1,155 @@ - KConfirmManualEnterDlgDecl - + KConfirmManualEnterDlg + 0 0 578 384 Confirm Manual Enter true 6 11 11 11 11 The following changes have been made to the transaction data: Qt::RichText false true Please choose what you wish to do with the above changes &Discard the changes and enter the original transaction into the register. buttonGroup1 Enter &these new values this one time, for this occurrence only. true buttonGroup1 Set all further occurrences &in this schedule to be these values. buttonGroup1 QDialogButtonBox::Cancel|QDialogButtonBox::Ok KTextEdit QTextEdit
ktextedit.h
buttonBox accepted() - KConfirmManualEnterDlgDecl + KConfirmManualEnterDlg accept() 456 361 177 380 buttonBox rejected() - KConfirmManualEnterDlgDecl + KConfirmManualEnterDlg reject() 487 359 479 380
diff --git a/kmymoney/dialogs/kcurrencycalculator.cpp b/kmymoney/dialogs/kcurrencycalculator.cpp index 64287437b..fbcc5d6d1 100644 --- a/kmymoney/dialogs/kcurrencycalculator.cpp +++ b/kmymoney/dialogs/kcurrencycalculator.cpp @@ -1,333 +1,384 @@ /*************************************************************************** kcurrencycalculator.cpp - description ------------------- begin : Thu Apr 8 2004 copyright : (C) 2000-2004 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kcurrencycalculator.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include #include -#include // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kcurrencycalculator.h" + #include "mymoneyfile.h" #include "mymoneyaccount.h" #include "mymoneysecurity.h" #include "kmymoneyedit.h" #include "kmymoneydateinput.h" #include "mymoneyprice.h" #include "mymoneymoney.h" #include "mymoneysplit.h" #include "mymoneytransaction.h" #include "kmymoneyglobalsettings.h" -#include "kmymoneyutils.h" +class KCurrencyCalculatorPrivate +{ + Q_DISABLE_COPY(KCurrencyCalculatorPrivate) + Q_DECLARE_PUBLIC(KCurrencyCalculator) + +public: + KCurrencyCalculatorPrivate(KCurrencyCalculator *qq, + const MyMoneySecurity& from, + const MyMoneySecurity& to, + const MyMoneyMoney& value, + const MyMoneyMoney& shares, + const QDate& date, + const signed64 resultFraction) : + q_ptr(qq), + ui(new Ui::KCurrencyCalculator), + m_fromCurrency(from), + m_toCurrency(to), + m_result(shares.abs()), + m_value(value.abs()), + m_date(date), + m_resultFraction(resultFraction) + { + } + + ~KCurrencyCalculatorPrivate() + { + delete ui; + } + + void init() + { + Q_Q(KCurrencyCalculator); + ui->setupUi(q); + auto file = MyMoneyFile::instance(); + + //set main widget of QDialog + ui->buttonGroup1->setId(ui->m_amountButton, 0); + ui->buttonGroup1->setId(ui->m_rateButton, 1); + + ui->m_dateFrame->hide(); + if (m_date.isValid()) + ui->m_dateEdit->setDate(m_date); + else + ui->m_dateEdit->setDate(QDate::currentDate()); + + ui->m_fromCurrencyText->setText(QString(MyMoneySecurity::securityTypeToString(m_fromCurrency.securityType()) + ' ' + (m_fromCurrency.isCurrency() ? m_fromCurrency.id() : m_fromCurrency.tradingSymbol()))); + ui->m_toCurrencyText->setText(QString(MyMoneySecurity::securityTypeToString(m_toCurrency.securityType()) + ' ' + (m_toCurrency.isCurrency() ? m_toCurrency.id() : m_toCurrency.tradingSymbol()))); + + //set bold font + auto boldFont = ui->m_fromCurrencyText->font(); + boldFont.setBold(true); + ui->m_fromCurrencyText->setFont(boldFont); + boldFont = ui->m_toCurrencyText->font(); + boldFont.setBold(true); + ui->m_toCurrencyText->setFont(boldFont); + + ui->m_fromAmount->setText(m_value.formatMoney(QString(), MyMoneyMoney::denomToPrec(m_fromCurrency.smallestAccountFraction()))); + + ui->m_dateText->setText(QLocale().toString(m_date)); + + ui->m_updateButton->setChecked(KMyMoneyGlobalSettings::priceHistoryUpdate()); + + // setup initial result + if (m_result == MyMoneyMoney() && !m_value.isZero()) { + const MyMoneyPrice &pr = file->price(m_fromCurrency.id(), m_toCurrency.id(), m_date); + if (pr.isValid()) { + m_result = m_value * pr.rate(m_toCurrency.id()); + } + } + + // fill in initial values + ui->m_toAmount->loadText(m_result.formatMoney(QString(), MyMoneyMoney::denomToPrec(m_resultFraction))); + ui->m_toAmount->setPrecision(MyMoneyMoney::denomToPrec(m_resultFraction)); + + ui->m_conversionRate->setPrecision(m_fromCurrency.pricePrecision()); + + q->connect(ui->m_amountButton, &QAbstractButton::clicked, q, &KCurrencyCalculator::slotSetToAmount); + q->connect(ui->m_rateButton, &QAbstractButton::clicked, q, &KCurrencyCalculator::slotSetExchangeRate); + + q->connect(ui->m_toAmount, &kMyMoneyEdit::valueChanged, q, &KCurrencyCalculator::slotUpdateResult); + q->connect(ui->m_conversionRate, &kMyMoneyEdit::valueChanged, q, &KCurrencyCalculator::slotUpdateRate); -bool KCurrencyCalculator::setupSplitPrice(MyMoneyMoney& shares, const MyMoneyTransaction& t, const MyMoneySplit& s, const QMap& priceInfo, QWidget* parentWidget) + // use this as the default + ui->m_amountButton->animateClick(); + q->slotUpdateResult(ui->m_toAmount->text()); + + // If the from security is not a currency, we only allow entering a price + if (!m_fromCurrency.isCurrency()) { + ui->m_rateButton->animateClick(); + ui->m_amountButton->hide(); + ui->m_toAmount->hide(); + } + } + + void updateExample(const MyMoneyMoney& price) + { + QString msg; + if (price.isZero()) { + msg = QString("1 %1 = ? %2").arg(m_fromCurrency.tradingSymbol()) + .arg(m_toCurrency.tradingSymbol()); + if (m_fromCurrency.isCurrency()) { + msg += QString("\n"); + msg += QString("1 %1 = ? %2").arg(m_toCurrency.tradingSymbol()) + .arg(m_fromCurrency.tradingSymbol()); + } + } else { + msg = QString("1 %1 = %2 %3").arg(m_fromCurrency.tradingSymbol()) + .arg(price.formatMoney(QString(), m_fromCurrency.pricePrecision())) + .arg(m_toCurrency.tradingSymbol()); + if (m_fromCurrency.isCurrency()) { + msg += QString("\n"); + msg += QString("1 %1 = %2 %3").arg(m_toCurrency.tradingSymbol()) + .arg((MyMoneyMoney::ONE / price).formatMoney(QString(), m_toCurrency.pricePrecision())) + .arg(m_fromCurrency.tradingSymbol()); + } + } + ui->m_conversionExample->setText(msg); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!price.isZero()); + } + + KCurrencyCalculator *q_ptr; + Ui::KCurrencyCalculator *ui; + MyMoneySecurity m_fromCurrency; + MyMoneySecurity m_toCurrency; + MyMoneyMoney m_result; + MyMoneyMoney m_value; + QDate m_date; + signed64 m_resultFraction; +}; + +KCurrencyCalculator::KCurrencyCalculator(const MyMoneySecurity& from, + const MyMoneySecurity& to, + const MyMoneyMoney& value, + const MyMoneyMoney& shares, + const QDate& date, + const signed64 resultFraction, + QWidget *parent) : + QDialog(parent), + d_ptr(new KCurrencyCalculatorPrivate(this, + from, + to, + value, + shares, + date, + resultFraction)) { - bool rc = true; - MyMoneyFile* file = MyMoneyFile::instance(); + Q_D(KCurrencyCalculator); + d->init(); +} + +KCurrencyCalculator::~KCurrencyCalculator() +{ + Q_D(KCurrencyCalculator); + delete d; +} + +bool KCurrencyCalculator::setupSplitPrice(MyMoneyMoney& shares, + const MyMoneyTransaction& t, + const MyMoneySplit& s, + const QMap& priceInfo, + QWidget* parentWidget) +{ + auto rc = true; + auto file = MyMoneyFile::instance(); if (!s.value().isZero()) { - MyMoneyAccount cat = file->account(s.accountId()); + auto cat = file->account(s.accountId()); MyMoneySecurity toCurrency; toCurrency = file->security(cat.currencyId()); // determine the fraction required for this category/account int fract = cat.fraction(toCurrency); if (cat.currencyId() != t.commodity()) { - MyMoneySecurity fromCurrency; - MyMoneyMoney fromValue, toValue; - fromCurrency = file->security(t.commodity()); + MyMoneyMoney toValue; + auto fromCurrency = file->security(t.commodity()); // display only positive values to the user - fromValue = s.value().abs(); + auto fromValue = s.value().abs(); // if we had a price info in the beginning, we use it here if (priceInfo.find(cat.currencyId()) != priceInfo.end()) { toValue = (fromValue * priceInfo[cat.currencyId()]).convert(fract); } // if the shares are still 0, we need to change that if (toValue.isZero()) { const MyMoneyPrice &price = file->price(fromCurrency.id(), toCurrency.id(), t.postDate()); // if the price is valid calculate the shares. If it is invalid // assume a conversion rate of 1.0 if (price.isValid()) { toValue = (price.rate(toCurrency.id()) * fromValue).convert(fract); } else { toValue = fromValue; } } // now present all that to the user QPointer calc = new KCurrencyCalculator(fromCurrency, toCurrency, fromValue, toValue, t.postDate(), fract, parentWidget); if (calc->exec() == QDialog::Rejected) { rc = false; } else shares = (s.value() * calc->price()).convert(fract); delete calc; } else { shares = s.value().convert(fract); } } else shares = s.value(); return rc; } -KCurrencyCalculator::KCurrencyCalculator(const MyMoneySecurity& from, const MyMoneySecurity& to, const MyMoneyMoney& value, const MyMoneyMoney& shares, const QDate& date, const signed64 resultFraction, QWidget *parent) : - KCurrencyCalculatorDecl(parent), - m_fromCurrency(from), - m_toCurrency(to), - m_result(shares.abs()), - m_value(value.abs()), - m_resultFraction(resultFraction), - m_buttonBox(0) -{ - MyMoneyFile* file = MyMoneyFile::instance(); - - //set main widget of QDialog - QVBoxLayout *mainLayout = new QVBoxLayout; - setLayout(mainLayout); - mainLayout->addWidget(m_layoutWidget); - - m_buttonBox = new QDialogButtonBox(this); - m_buttonBox->setStandardButtons(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); - QPushButton *okButton = m_buttonBox->button(QDialogButtonBox::Ok); - okButton->setDefault(true); - /// @todo remove Ctrl-Enter behavior in future release - okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - mainLayout->addWidget(m_buttonBox); - - buttonGroup1->setId(m_amountButton, 0); - buttonGroup1->setId(m_rateButton, 1); - - m_dateFrame->hide(); - if (date.isValid()) - m_dateEdit->setDate(date); - else - m_dateEdit->setDate(QDate::currentDate()); - - m_fromCurrencyText->setText(QString(MyMoneySecurity::securityTypeToString(m_fromCurrency.securityType()) + ' ' + (m_fromCurrency.isCurrency() ? m_fromCurrency.id() : m_fromCurrency.tradingSymbol()))); - m_toCurrencyText->setText(QString(MyMoneySecurity::securityTypeToString(m_toCurrency.securityType()) + ' ' + (m_toCurrency.isCurrency() ? m_toCurrency.id() : m_toCurrency.tradingSymbol()))); - - //set bold font - QFont boldFont = m_fromCurrencyText->font(); - boldFont.setBold(true); - m_fromCurrencyText->setFont(boldFont); - boldFont = m_toCurrencyText->font(); - boldFont.setBold(true); - m_toCurrencyText->setFont(boldFont); - - m_fromAmount->setText(m_value.formatMoney(QString(), MyMoneyMoney::denomToPrec(m_fromCurrency.smallestAccountFraction()))); - - m_dateText->setText(QLocale().toString(date)); - - m_updateButton->setChecked(KMyMoneyGlobalSettings::priceHistoryUpdate()); - - // setup initial result - if (m_result == MyMoneyMoney() && !m_value.isZero()) { - const MyMoneyPrice &pr = file->price(m_fromCurrency.id(), m_toCurrency.id(), date); - if (pr.isValid()) { - m_result = m_value * pr.rate(m_toCurrency.id()); - } - } - - // fill in initial values - m_toAmount->loadText(m_result.formatMoney(QString(), MyMoneyMoney::denomToPrec(m_resultFraction))); - m_toAmount->setPrecision(MyMoneyMoney::denomToPrec(m_resultFraction)); - - m_conversionRate->setPrecision(m_fromCurrency.pricePrecision()); - - connect(m_amountButton, SIGNAL(clicked()), this, SLOT(slotSetToAmount())); - connect(m_rateButton, SIGNAL(clicked()), this, SLOT(slotSetExchangeRate())); - - connect(m_toAmount, SIGNAL(valueChanged(QString)), this, SLOT(slotUpdateResult(QString))); - connect(m_conversionRate, SIGNAL(valueChanged(QString)), this, SLOT(slotUpdateRate(QString))); - - // use this as the default - m_amountButton->animateClick(); - slotUpdateResult(m_toAmount->text()); - - // If the from security is not a currency, we only allow entering a price - if (!m_fromCurrency.isCurrency()) { - m_rateButton->animateClick(); - m_amountButton->hide(); - m_toAmount->hide(); - } - okButton->setFocus(); -} - -KCurrencyCalculator::~KCurrencyCalculator() -{ -} - void KCurrencyCalculator::setupPriceEditor() { - m_dateFrame->show(); - m_amountDateFrame->hide(); - m_updateButton->setChecked(true); - m_updateButton->hide(); + Q_D(KCurrencyCalculator); + d->ui->m_dateFrame->show(); + d->ui->m_amountDateFrame->hide(); + d->ui->m_updateButton->setChecked(true); + d->ui->m_updateButton->hide(); } void KCurrencyCalculator::slotSetToAmount() { - m_rateButton->setChecked(false); - m_toAmount->setEnabled(true); - m_conversionRate->setEnabled(false); + Q_D(KCurrencyCalculator); + d->ui->m_rateButton->setChecked(false); + d->ui->m_toAmount->setEnabled(true); + d->ui->m_conversionRate->setEnabled(false); } void KCurrencyCalculator::slotSetExchangeRate() { - m_amountButton->setChecked(false); - m_toAmount->setEnabled(false); - m_conversionRate->setEnabled(true); + Q_D(KCurrencyCalculator); + d->ui->m_amountButton->setChecked(false); + d->ui->m_toAmount->setEnabled(false); + d->ui->m_conversionRate->setEnabled(true); } void KCurrencyCalculator::slotUpdateResult(const QString& /*txt*/) { - MyMoneyMoney result = m_toAmount->value(); + Q_D(KCurrencyCalculator); + MyMoneyMoney result = d->ui->m_toAmount->value(); MyMoneyMoney price(0, 1); if (result.isNegative()) { - m_toAmount->setValue(-result); + d->ui->m_toAmount->setValue(-result); slotUpdateResult(QString()); return; } if (!result.isZero()) { - price = result / m_value; + price = result / d->m_value; - m_conversionRate->loadText(price.formatMoney(QString(), m_fromCurrency.pricePrecision())); - m_result = (m_value * price).convert(m_resultFraction); - m_toAmount->loadText(m_result.formatMoney(m_resultFraction)); + d->ui->m_conversionRate->loadText(price.formatMoney(QString(), d->m_fromCurrency.pricePrecision())); + d->m_result = (d->m_value * price).convert(d->m_resultFraction); + d->ui->m_toAmount->loadText(d->m_result.formatMoney(d->m_resultFraction)); } - updateExample(price); + d->updateExample(price); } void KCurrencyCalculator::slotUpdateRate(const QString& /*txt*/) { - MyMoneyMoney price = m_conversionRate->value(); + Q_D(KCurrencyCalculator); + auto price = d->ui->m_conversionRate->value(); if (price.isNegative()) { - m_conversionRate->setValue(-price); + d->ui->m_conversionRate->setValue(-price); slotUpdateRate(QString()); return; } if (!price.isZero()) { - m_conversionRate->loadText(price.formatMoney(QString(), m_fromCurrency.pricePrecision())); - m_result = (m_value * price).convert(m_resultFraction); - m_toAmount->loadText(m_result.formatMoney(QString(), MyMoneyMoney::denomToPrec(m_resultFraction))); + d->ui->m_conversionRate->loadText(price.formatMoney(QString(), d->m_fromCurrency.pricePrecision())); + d->m_result = (d->m_value * price).convert(d->m_resultFraction); + d->ui->m_toAmount->loadText(d->m_result.formatMoney(QString(), MyMoneyMoney::denomToPrec(d->m_resultFraction))); } - updateExample(price); -} - -void KCurrencyCalculator::updateExample(const MyMoneyMoney& price) -{ - QString msg; - if (price.isZero()) { - msg = QString("1 %1 = ? %2").arg(m_fromCurrency.tradingSymbol()) - .arg(m_toCurrency.tradingSymbol()); - if (m_fromCurrency.isCurrency()) { - msg += QString("\n"); - msg += QString("1 %1 = ? %2").arg(m_toCurrency.tradingSymbol()) - .arg(m_fromCurrency.tradingSymbol()); - } - } else { - msg = QString("1 %1 = %2 %3").arg(m_fromCurrency.tradingSymbol()) - .arg(price.formatMoney(QString(), m_fromCurrency.pricePrecision())) - .arg(m_toCurrency.tradingSymbol()); - if (m_fromCurrency.isCurrency()) { - msg += QString("\n"); - msg += QString("1 %1 = %2 %3").arg(m_toCurrency.tradingSymbol()) - .arg((MyMoneyMoney::ONE / price).formatMoney(QString(), m_toCurrency.pricePrecision())) - .arg(m_fromCurrency.tradingSymbol()); - } - } - m_conversionExample->setText(msg); - m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!price.isZero()); + d->updateExample(price); } void KCurrencyCalculator::accept() { - if (m_conversionRate->isEnabled()) + Q_D(KCurrencyCalculator); + if (d->ui->m_conversionRate->isEnabled()) slotUpdateRate(QString()); else slotUpdateResult(QString()); - if (m_updateButton->isChecked()) { - MyMoneyPrice pr = MyMoneyFile::instance()->price(m_fromCurrency.id(), m_toCurrency.id(), m_dateEdit->date()); + if (d->ui->m_updateButton->isChecked()) { + auto pr = MyMoneyFile::instance()->price(d->m_fromCurrency.id(), d->m_toCurrency.id(), d->ui->m_dateEdit->date()); if (!pr.isValid() - || pr.date() != m_dateEdit->date() - || (pr.date() == m_dateEdit->date() && pr.rate(m_fromCurrency.id()) != price())) { - pr = MyMoneyPrice(m_fromCurrency.id(), m_toCurrency.id(), m_dateEdit->date(), price(), i18n("User")); + || pr.date() != d->ui->m_dateEdit->date() + || (pr.date() == d->ui->m_dateEdit->date() && pr.rate(d->m_fromCurrency.id()) != price())) { + pr = MyMoneyPrice(d->m_fromCurrency.id(), d->m_toCurrency.id(), d->ui->m_dateEdit->date(), price(), i18n("User")); MyMoneyFileTransaction ft; try { MyMoneyFile::instance()->addPrice(pr); ft.commit(); } catch (const MyMoneyException &) { qDebug("Cannot add price"); } } } // remember setting for next round - KMyMoneyGlobalSettings::setPriceHistoryUpdate(m_updateButton->isChecked()); - - KCurrencyCalculatorDecl::accept(); + KMyMoneyGlobalSettings::setPriceHistoryUpdate(d->ui->m_updateButton->isChecked()); + QDialog::accept(); } MyMoneyMoney KCurrencyCalculator::price() const { + Q_D(const KCurrencyCalculator); // This should fix https://bugs.kde.org/show_bug.cgi?id=205254 and // https://bugs.kde.org/show_bug.cgi?id=325953 as well as // https://bugs.kde.org/show_bug.cgi?id=300965 - if (m_amountButton->isChecked()) - return m_toAmount->value().abs() / m_value.abs(); + if (d->ui->m_amountButton->isChecked()) + return d->ui->m_toAmount->value().abs() / d->m_value.abs(); else - return m_conversionRate->value(); + return d->ui->m_conversionRate->value(); } diff --git a/kmymoney/dialogs/kcurrencycalculator.h b/kmymoney/dialogs/kcurrencycalculator.h index 9f06a6fd5..37f855f97 100644 --- a/kmymoney/dialogs/kcurrencycalculator.h +++ b/kmymoney/dialogs/kcurrencycalculator.h @@ -1,111 +1,114 @@ /*************************************************************************** kcurrencycalculator.h - description ------------------- begin : Thu Apr 8 2004 copyright : (C) 2000-2004 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KCURRENCYCALCULATOR_H #define KCURRENCYCALCULATOR_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_kcurrencycalculatordecl.h" -#include "mymoneymoney.h" -#include "mymoneysecurity.h" +class QDate; +class MyMoneyMoney; class MyMoneySplit; class MyMoneyTransaction; -class QDialogButtonBox; +class MyMoneySecurity; + +namespace Ui { class KCurrencyCalculator; } + +typedef qint64 signed64; /** * @author Thomas Baumgart */ -class KCurrencyCalculatorDecl : public QDialog, public Ui::KCurrencyCalculatorDecl -{ -public: - KCurrencyCalculatorDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; -class KCurrencyCalculator : public KCurrencyCalculatorDecl +class KCurrencyCalculatorPrivate; +class KCurrencyCalculator : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KCurrencyCalculator) public: /** * @param from the @p from currency * @param to the @p to currency * @param value the value to be converted * @param shares the number of foreign currency units * @param date the date when the conversion took place * @param resultFraction the smallest fraction of the result (default 100) * @param parent see QWidget constructor * * @note @p value must not be 0! */ - KCurrencyCalculator(const MyMoneySecurity& from, const MyMoneySecurity& to, const MyMoneyMoney& value, const MyMoneyMoney& shares, const QDate& date, const signed64 resultFraction = 100, QWidget *parent = 0); + explicit KCurrencyCalculator(const MyMoneySecurity& from, + const MyMoneySecurity& to, + const MyMoneyMoney& value, + const MyMoneyMoney& shares, + const QDate& date, + const signed64 resultFraction = 100, + QWidget *parent = nullptr); ~KCurrencyCalculator(); /** * This method returns the price determined by the method selected by the user * which is either * * a) based on the resulting amount or * b) based on direct price entry. * * In case a) the price is returned without precision loss as the devision * of the amount entered by the user and the @a value passed as argument. * In case b) it is returned with the selected global price precision. */ MyMoneyMoney price() const; void setupPriceEditor(); - static bool setupSplitPrice(MyMoneyMoney& shares, const MyMoneyTransaction& t, const MyMoneySplit& s, const QMap& priceInfo, QWidget* parentWidget); - -protected: - void updateExample(const MyMoneyMoney& price); + static bool setupSplitPrice(MyMoneyMoney& shares, + const MyMoneyTransaction& t, + const MyMoneySplit& s, + const QMap& priceInfo, + QWidget* parentWidget); protected slots: void slotSetToAmount(); void slotSetExchangeRate(); void slotUpdateResult(const QString& txt); void slotUpdateRate(const QString& txt); - virtual void accept(); + void accept() override; private: - MyMoneySecurity m_fromCurrency; - MyMoneySecurity m_toCurrency; - MyMoneyMoney m_result; - MyMoneyMoney m_value; - signed64 m_resultFraction; - QDialogButtonBox *m_buttonBox; + KCurrencyCalculatorPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KCurrencyCalculator) }; #endif diff --git a/kmymoney/dialogs/kcurrencycalculator.ui b/kmymoney/dialogs/kcurrencycalculator.ui new file mode 100644 index 000000000..5cc298eef --- /dev/null +++ b/kmymoney/dialogs/kcurrencycalculator.ui @@ -0,0 +1,400 @@ + + + KCurrencyCalculator + + + true + + + + 0 + 0 + 387 + 268 + + + + Exchange Rate/Price Editor + + + true + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Amount + + + false + + + + + + + xxx + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 80 + 20 + + + + + + + + Date + + + false + + + + + + + xxx + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 145 + 20 + + + + + + + + + + + + + + + Convert + + + + 0 + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + to + + + Qt::AlignCenter + + + false + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + + + + + + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + To a&mount + + + buttonGroup1 + + + + + + + Exchange &rate / Price + + + buttonGroup1 + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Date + + + false + + + + + + + + + + + + + xx +xx + + + false + + + + + + + + + + + + Update price history + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 16 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + kMyMoneyDateInput + QWidget +
kmymoneydateinput.h
+ 1 +
+ + kMyMoneyEdit + QWidget +
kmymoneyedit.h
+
+
+ + m_amountButton + m_rateButton + m_updateButton + + + + + buttonBox + accepted() + KCurrencyCalculator + accept() + + + 189 + 233 + + + 193 + 133 + + + + + buttonBox + rejected() + KCurrencyCalculator + reject() + + + 189 + 233 + + + 193 + 133 + + + + + + + +
diff --git a/kmymoney/dialogs/kcurrencycalculatordecl.ui b/kmymoney/dialogs/kcurrencycalculatordecl.ui deleted file mode 100644 index dfa9204c4..000000000 --- a/kmymoney/dialogs/kcurrencycalculatordecl.ui +++ /dev/null @@ -1,317 +0,0 @@ - - - - - - KCurrencyCalculatorDecl - - - true - - - - 0 - 0 - 387 - 268 - - - - Exchange Rate/Price Editor - - - true - - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - - 0 - - - - - - - Amount - - - false - - - - - - - xxx - - - false - - - - - - - - 80 - 20 - - - - QSizePolicy::Expanding - - - Qt::Horizontal - - - - - - - Date - - - false - - - - - - - xxx - - - false - - - - - - - - 145 - 20 - - - - QSizePolicy::Expanding - - - Qt::Horizontal - - - - - - - - - - - - - - Convert - - - - 0 - - - - - - - - Qt::AlignVCenter|Qt::AlignLeft - - - false - - - - - - - to - - - Qt::AlignVCenter|Qt::AlignHCenter - - - false - - - - - - - - - - Qt::AlignVCenter|Qt::AlignRight - - - false - - - - - - - - - - - - - - - - - - - - true - - - - 0 - - - - - QFrame::NoFrame - - - QFrame::Plain - - - - 0 - - - - - To amount - - - buttonGroup1 - - - - - - - Exchange rate / Price - - - buttonGroup1 - - - - - - - - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - - 0 - - - - - Date - - - false - - - - - - - - - - - - - xx -xx - - - false - - - - - - - - - - - - Update price history - - - true - - - - - - - - 20 - 16 - - - - QSizePolicy::Expanding - - - Qt::Vertical - - - - - - - - - m_amountButton - m_rateButton - m_updateButton - - - - - - - QDialog - QDialog -
kdialog.h
-
-
-
diff --git a/kmymoney/dialogs/kcurrencyeditdlg.cpp b/kmymoney/dialogs/kcurrencyeditdlg.cpp index 6fd928b11..bc792993a 100644 --- a/kmymoney/dialogs/kcurrencyeditdlg.cpp +++ b/kmymoney/dialogs/kcurrencyeditdlg.cpp @@ -1,386 +1,447 @@ /*************************************************************************** kcurrencyeditdlg.cpp - description ------------------- begin : Wed Mar 24 2004 copyright : (C) 2000-2004 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio Alvaro Soliverez (C) 2017 Ł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. * * * ***************************************************************************/ #include "kcurrencyeditdlg.h" #include // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes #include "ui_kcurrencyeditdlg.h" #include "ui_kcurrencyeditordlg.h" #include "ui_kavailablecurrencydlg.h" #include "mymoneysecurity.h" #include "mymoneyfile.h" #include "mymoneyprice.h" #include "kavailablecurrencydlg.h" #include "kcurrencyeditordlg.h" #include "kmymoneyutils.h" #include "icons/icons.h" #include "storageenums.h" using namespace Icons; // this delegate is needed to disable editing the currency id (column 1) // since QTreeWidgetItem has only one set of flags for the whole row // the column editable property couldn't be set in an easier way class KCurrencyEditDelegate : public QStyledItemDelegate { public: explicit KCurrencyEditDelegate(QObject *parent = 0); protected: QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; }; KCurrencyEditDelegate::KCurrencyEditDelegate(QObject* parent): QStyledItemDelegate(parent) { } QWidget *KCurrencyEditDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (index.column() == 1) return 0; return QStyledItemDelegate::createEditor(parent, option, index); } -KCurrencyEditDlg::KCurrencyEditDlg(QWidget *parent) : ui(new Ui::KCurrencyEditDlg) +class KCurrencyEditDlgPrivate { - Q_UNUSED(parent); - ui->setupUi(this); - m_searchWidget = new KTreeWidgetSearchLineWidget(this, ui->m_currencyList); - m_searchWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); - m_searchWidget->setFocus(); - ui->verticalLayout->insertWidget(0, m_searchWidget); - ui->m_currencyList->setItemDelegate(new KCurrencyEditDelegate(ui->m_currencyList)); - ui->m_closeButton->setIcon(QIcon::fromTheme(g_Icons[Icon::DialogClose])); - ui->m_editCurrencyButton->setIcon(QIcon::fromTheme(g_Icons[Icon::DocumentEdit])); - ui->m_selectBaseCurrencyButton->setIcon(QIcon::fromTheme(g_Icons[Icon::KMyMoney])); - - connect(ui->m_currencyList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotOpenContextMenu(QPoint))); - connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadCurrencies())); - connect(ui->m_currencyList, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(slotUpdateCurrency(QTreeWidgetItem*))); - connect(ui->m_currencyList, SIGNAL(itemSelectionChanged()), this, SLOT(slotItemSelectionChanged())); - - connect(ui->m_selectBaseCurrencyButton, SIGNAL(clicked()), this, SLOT(slotSelectBaseCurrency())); - connect(ui->m_addCurrencyButton, SIGNAL(clicked()), this, SLOT(slotAddCurrency())); - connect(ui->m_removeCurrencyButton, SIGNAL(clicked()), this, SLOT(slotRemoveCurrency())); - connect(ui->m_editCurrencyButton, SIGNAL(clicked()), this, SLOT(slotEditCurrency())); - connect(ui->m_removeUnusedCurrencyButton, SIGNAL(clicked()), this, SLOT(slotRemoveUnusedCurrency())); + Q_DISABLE_COPY(KCurrencyEditDlgPrivate) + Q_DECLARE_PUBLIC(KCurrencyEditDlg) + +public: + KCurrencyEditDlgPrivate(KCurrencyEditDlg *qq) : + q_ptr(qq), + ui(new Ui::KCurrencyEditDlg) + { + } + + ~KCurrencyEditDlgPrivate() + { + delete ui; + } + + enum removalModeE :int { RemoveSelected, RemoveUnused }; + + void removeCurrency(const removalModeE& mode) + { + Q_Q(KCurrencyEditDlg); + auto file = MyMoneyFile::instance(); + MyMoneyFileTransaction ft; + QBitArray skip((int)eStorage::Reference::Count); + skip.fill(false); // check reference to all... + skip.setBit((int)eStorage::Reference::Price); // ...except price + + QTreeWidgetItemIterator it (ui->m_currencyList); // iterate over whole tree + if (mode == RemoveUnused) { + while (*it) { + MyMoneySecurity currency = (*it)->data(0, Qt::UserRole).value(); + if (file->baseCurrency() != currency && !file->isReferenced(currency, skip)) + KMyMoneyUtils::deleteSecurity(currency, q); + ++it; + } + } else if (mode == RemoveSelected) { + QList currencyRows = ui->m_currencyList->selectedItems(); + foreach(auto currencyRow, currencyRows) { + MyMoneySecurity currency = currencyRow->data(0, Qt::UserRole).value(); + if (file->baseCurrency() != currency && !file->isReferenced(currency, skip)) + KMyMoneyUtils::deleteSecurity(currency, q); + } + } + ft.commit(); + ui->m_removeUnusedCurrencyButton->setDisabled(file->currencyList().count() <= 1); + } + + KCurrencyEditDlg *q_ptr; + Ui::KCurrencyEditDlg *ui; + + KAvailableCurrencyDlg *m_availableCurrencyDlg; + KCurrencyEditorDlg *m_currencyEditorDlg; + MyMoneySecurity m_currency; + /** + * Search widget for the list + */ + KTreeWidgetSearchLineWidget* m_searchWidget; +}; + +KCurrencyEditDlg::KCurrencyEditDlg(QWidget *parent) : + QDialog(parent), + d_ptr(new KCurrencyEditDlgPrivate(this)) +{ + Q_D(KCurrencyEditDlg); + d->ui->setupUi(this); + d->m_searchWidget = new KTreeWidgetSearchLineWidget(this, d->ui->m_currencyList); + d->m_searchWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); + d->m_searchWidget->setFocus(); + d->ui->verticalLayout->insertWidget(0, d->m_searchWidget); + d->ui->m_currencyList->setItemDelegate(new KCurrencyEditDelegate(d->ui->m_currencyList)); + d->ui->m_closeButton->setIcon(QIcon::fromTheme(g_Icons[Icon::DialogClose])); + d->ui->m_editCurrencyButton->setIcon(QIcon::fromTheme(g_Icons[Icon::DocumentEdit])); + d->ui->m_selectBaseCurrencyButton->setIcon(QIcon::fromTheme(g_Icons[Icon::KMyMoney])); + + connect(d->ui->m_currencyList, &QWidget::customContextMenuRequested, this, &KCurrencyEditDlg::slotOpenContextMenu); + connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, this, &KCurrencyEditDlg::slotLoadCurrencies); + connect(d->ui->m_currencyList, &QTreeWidget::itemChanged, this, static_cast(&KCurrencyEditDlg::slotUpdateCurrency)); + connect(d->ui->m_currencyList, &QTreeWidget::itemSelectionChanged, this, &KCurrencyEditDlg::slotItemSelectionChanged); + + connect(d->ui->m_selectBaseCurrencyButton, &QAbstractButton::clicked, this, &KCurrencyEditDlg::slotSelectBaseCurrency); + connect(d->ui->m_addCurrencyButton, &QAbstractButton::clicked, this, &KCurrencyEditDlg::slotAddCurrency); + connect(d->ui->m_removeCurrencyButton, &QAbstractButton::clicked, this, &KCurrencyEditDlg::slotRemoveCurrency); + connect(d->ui->m_editCurrencyButton, &QAbstractButton::clicked, this, &KCurrencyEditDlg::slotEditCurrency); + connect(d->ui->m_removeUnusedCurrencyButton, &QAbstractButton::clicked, this, &KCurrencyEditDlg::slotRemoveUnusedCurrency); QTimer::singleShot(10, this, SLOT(timerDone())); } void KCurrencyEditDlg::timerDone() { + Q_D(KCurrencyEditDlg); slotLoadCurrencies(); //resize the column widths - for (int i = 0; i < 3; ++i) - ui->m_currencyList->resizeColumnToContents(i); + for (auto i = 0; i < 3; ++i) + d->ui->m_currencyList->resizeColumnToContents(i); - if (!m_currency.id().isEmpty()) { - QTreeWidgetItemIterator it(ui->m_currencyList); + if (!d->m_currency.id().isEmpty()) { + QTreeWidgetItemIterator it(d->ui->m_currencyList); QTreeWidgetItem* q; while ((q = *it) != 0) { - if (q->text(1) == m_currency.id()) { - ui->m_currencyList->scrollToItem(q); + if (q->text(1) == d->m_currency.id()) { + d->ui->m_currencyList->scrollToItem(q); break; } ++it; } } } KCurrencyEditDlg::~KCurrencyEditDlg() { + Q_D(KCurrencyEditDlg); + delete d; } void KCurrencyEditDlg::slotLoadCurrencies() { - disconnect(ui->m_currencyList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotSelectCurrency(QTreeWidgetItem*))); - disconnect(ui->m_currencyList, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(slotUpdateCurrency(QTreeWidgetItem*))); + Q_D(KCurrencyEditDlg); + disconnect(d->ui->m_currencyList, &QTreeWidget::currentItemChanged, this, static_cast(&KCurrencyEditDlg::slotSelectCurrency)); + disconnect(d->ui->m_currencyList, &QTreeWidget::itemChanged, this, static_cast(&KCurrencyEditDlg::slotUpdateCurrency)); QList list = MyMoneyFile::instance()->currencyList(); QList::ConstIterator it; QTreeWidgetItem *first = 0; QString localCurrency(localeconv()->int_curr_symbol); localCurrency.truncate(3); QString baseCurrency; try { baseCurrency = MyMoneyFile::instance()->baseCurrency().id(); } catch (const MyMoneyException &e) { qDebug("%s", qPrintable(e.what())); } // construct a transparent 16x16 pixmap QPixmap empty(16, 16); QBitmap mask(16, 16); mask.clear(); empty.setMask(mask); - ui->m_currencyList->clear(); + d->ui->m_currencyList->clear(); for (it = list.constBegin(); it != list.constEnd(); ++it) { - QTreeWidgetItem *p = new QTreeWidgetItem(ui->m_currencyList); + QTreeWidgetItem *p = new QTreeWidgetItem(d->ui->m_currencyList); p->setText(0, (*it).name()); p->setData(0, Qt::UserRole, QVariant::fromValue(*it)); p->setFlags(p->flags() | Qt::ItemIsEditable); p->setText(1, (*it).id()); p->setText(2, (*it).tradingSymbol()); if ((*it).id() == baseCurrency) { p->setData(0, Qt::DecorationRole, QIcon::fromTheme(g_Icons[Icon::KMyMoney])); - if (m_currency.id().isEmpty()) + if (d->m_currency.id().isEmpty()) first = p; } else { p->setData(0, Qt::DecorationRole, empty); } // if we had a previously selected - if (!m_currency.id().isEmpty()) { - if (m_currency.id() == p->text(1)) + if (!d->m_currency.id().isEmpty()) { + if (d->m_currency.id() == p->text(1)) first = p; } else if ((*it).id() == localCurrency && !first) first = p; } - ui->m_removeUnusedCurrencyButton->setDisabled(list.count() <= 1); - ui->m_currencyList->sortItems(0, Qt::AscendingOrder); + d->ui->m_removeUnusedCurrencyButton->setDisabled(list.count() <= 1); + d->ui->m_currencyList->sortItems(0, Qt::AscendingOrder); - connect(ui->m_currencyList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotSelectCurrency(QTreeWidgetItem*))); - connect(ui->m_currencyList, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(slotUpdateCurrency(QTreeWidgetItem*))); + connect(d->ui->m_currencyList, &QTreeWidget::currentItemChanged, this, static_cast(&KCurrencyEditDlg::slotSelectCurrency)); + connect(d->ui->m_currencyList, &QTreeWidget::itemChanged, this, static_cast(&KCurrencyEditDlg::slotUpdateCurrency)); if (first == 0) - first = ui->m_currencyList->invisibleRootItem()->child(0); + first = d->ui->m_currencyList->invisibleRootItem()->child(0); if (first != 0) { - ui->m_currencyList->setCurrentItem(first); - ui->m_currencyList->scrollToItem(first); + d->ui->m_currencyList->setCurrentItem(first); + d->ui->m_currencyList->scrollToItem(first); } slotSelectCurrency(first); } -void KCurrencyEditDlg::slotUpdateCurrency(QTreeWidgetItem* item) +void KCurrencyEditDlg::slotUpdateCurrency(QTreeWidgetItem* citem, int) +{ + slotUpdateCurrency(citem, nullptr); +} + +void KCurrencyEditDlg::slotUpdateCurrency(QTreeWidgetItem* citem, QTreeWidgetItem *pitem) { + Q_D(KCurrencyEditDlg); + Q_UNUSED(pitem) //if there is no current item selected, exit - if (!ui->m_currencyList->currentItem() || item != ui->m_currencyList->currentItem()) + if (!d->ui->m_currencyList->currentItem() || citem != d->ui->m_currencyList->currentItem()) return; //verify that the stored currency id is not empty and the edited fields are not empty either - if (!m_currency.id().isEmpty() - && !ui->m_currencyList->currentItem()->text(2).isEmpty() - && !ui->m_currencyList->currentItem()->text(0).isEmpty()) { + if (!d->m_currency.id().isEmpty() + && !d->ui->m_currencyList->currentItem()->text(2).isEmpty() + && !d->ui->m_currencyList->currentItem()->text(0).isEmpty()) { //check that either the name or the id have changed - if (ui->m_currencyList->currentItem()->text(2) != m_currency.tradingSymbol() - || ui->m_currencyList->currentItem()->text(0) != m_currency.name()) { + if (d->ui->m_currencyList->currentItem()->text(2) != d->m_currency.tradingSymbol() + || d->ui->m_currencyList->currentItem()->text(0) != d->m_currency.name()) { //update the name and the id - m_currency.setName(ui->m_currencyList->currentItem()->text(0)); - m_currency.setTradingSymbol(ui->m_currencyList->currentItem()->text(2)); + d->m_currency.setName(d->ui->m_currencyList->currentItem()->text(0)); + d->m_currency.setTradingSymbol(d->ui->m_currencyList->currentItem()->text(2)); - emit updateCurrency(m_currency.id(), m_currency.name(), m_currency.tradingSymbol()); + emit updateCurrency(d->m_currency.id(), d->m_currency.name(), d->m_currency.tradingSymbol()); } } } void KCurrencyEditDlg::slotSelectCurrency(const QString& id) { - QTreeWidgetItemIterator it(ui->m_currencyList); + Q_D(KCurrencyEditDlg); + QTreeWidgetItemIterator it(d->ui->m_currencyList); while (*it) { if ((*it)->text(1) == id) { - ui->m_currencyList->blockSignals(true); + d->ui->m_currencyList->blockSignals(true); slotSelectCurrency(*it); - ui->m_currencyList->setCurrentItem(*it); - ui->m_currencyList->scrollToItem(*it); - ui->m_currencyList->blockSignals(false); + d->ui->m_currencyList->setCurrentItem(*it); + d->ui->m_currencyList->scrollToItem(*it); + d->ui->m_currencyList->blockSignals(false); break; } ++it; } } +void KCurrencyEditDlg::slotSelectCurrency(QTreeWidgetItem *citem, QTreeWidgetItem *pitem) +{ + Q_UNUSED(pitem) + slotSelectCurrency(citem); +} + void KCurrencyEditDlg::slotSelectCurrency(QTreeWidgetItem *item) { - MyMoneyFile* file = MyMoneyFile::instance(); + Q_D(KCurrencyEditDlg); + auto file = MyMoneyFile::instance(); QString baseId; try { baseId = MyMoneyFile::instance()->baseCurrency().id(); } catch (const MyMoneyException &) { } if (item) { try { - m_currency = file->security(item->text(1)); + d->m_currency = file->security(item->text(1)); } catch (const MyMoneyException &) { - m_currency = MyMoneySecurity(); + d->m_currency = MyMoneySecurity(); } QBitArray skip((int)eStorage::Reference::Count); skip.fill(false); skip.setBit((int)eStorage::Reference::Price); - const bool rc1 = m_currency.id() == baseId; - const bool rc2 = file->isReferenced(m_currency, skip); - const int count = ui->m_currencyList->selectedItems().count(); + const bool rc1 = d->m_currency.id() == baseId; + const bool rc2 = file->isReferenced(d->m_currency, skip); + const int count = d->ui->m_currencyList->selectedItems().count(); - ui->m_selectBaseCurrencyButton->setDisabled(rc1 || count != 1); - ui->m_editCurrencyButton->setDisabled(count != 1); - ui->m_removeCurrencyButton->setDisabled((rc1 || rc2) && count <= 1); - emit selectObject(m_currency); + d->ui->m_selectBaseCurrencyButton->setDisabled(rc1 || count != 1); + d->ui->m_editCurrencyButton->setDisabled(count != 1); + d->ui->m_removeCurrencyButton->setDisabled((rc1 || rc2) && count <= 1); + emit selectObject(d->m_currency); } } void KCurrencyEditDlg::slotItemSelectionChanged() { - int count = ui->m_currencyList->selectedItems().count(); - if (!ui->m_selectBaseCurrencyButton->isEnabled() && count == 1) - slotSelectCurrency(ui->m_currencyList->currentItem()); + Q_D(KCurrencyEditDlg); + int count = d->ui->m_currencyList->selectedItems().count(); + if (!d->ui->m_selectBaseCurrencyButton->isEnabled() && count == 1) + slotSelectCurrency(d->ui->m_currencyList->currentItem()); if (count > 1) - ui->m_removeCurrencyButton->setEnabled(true); + d->ui->m_removeCurrencyButton->setEnabled(true); } void KCurrencyEditDlg::slotStartRename() { - QTreeWidgetItemIterator it_l(ui->m_currencyList, QTreeWidgetItemIterator::Selected); + Q_D(KCurrencyEditDlg); + QTreeWidgetItemIterator it_l(d->ui->m_currencyList, QTreeWidgetItemIterator::Selected); QTreeWidgetItem* it_v; if ((it_v = *it_l) != 0) { - ui->m_currencyList->editItem(it_v, 0); + d->ui->m_currencyList->editItem(it_v, 0); } } void KCurrencyEditDlg::slotOpenContextMenu(const QPoint& p) { - QTreeWidgetItem* item = ui->m_currencyList->itemAt(p); + Q_D(KCurrencyEditDlg); + QTreeWidgetItem* item = d->ui->m_currencyList->itemAt(p); if (item) emit openContextMenu(item->data(0, Qt::UserRole).value()); } void KCurrencyEditDlg::slotSelectBaseCurrency() { - if (!m_currency.id().isEmpty()) { - QTreeWidgetItem* p = ui->m_currencyList->currentItem(); - emit selectBaseCurrency(m_currency); + Q_D(KCurrencyEditDlg); + if (!d->m_currency.id().isEmpty()) { + QTreeWidgetItem* p = d->ui->m_currencyList->currentItem(); + emit selectBaseCurrency(d->m_currency); // in case the dataChanged() signal was not sent out (nested FileTransaction) // we update the list manually - if (p == ui->m_currencyList->currentItem()) + if (p == d->ui->m_currencyList->currentItem()) slotLoadCurrencies(); } } void KCurrencyEditDlg::slotAddCurrency() { - m_availableCurrencyDlg = new KAvailableCurrencyDlg; // create new dialog for selecting currencies to add - if (m_availableCurrencyDlg->exec() != QDialog::Rejected) { - MyMoneyFile* file = MyMoneyFile::instance(); + Q_D(KCurrencyEditDlg); + d->m_availableCurrencyDlg = new KAvailableCurrencyDlg; // create new dialog for selecting currencies to add + if (d->m_availableCurrencyDlg->exec() != QDialog::Rejected) { + auto file = MyMoneyFile::instance(); QMap ancientCurrencies = file->ancientCurrencies(); MyMoneyFileTransaction ft; - QList currencyRows = m_availableCurrencyDlg->ui->m_currencyList->selectedItems(); // get selected currencies from new dialog + QList currencyRows = d->m_availableCurrencyDlg->ui->m_currencyList->selectedItems(); // get selected currencies from new dialog foreach (auto currencyRow, currencyRows) { MyMoneySecurity currency = currencyRow->data(0, Qt::UserRole).value(); file->addCurrency(currency); if (ancientCurrencies.value(currency, MyMoneyPrice()) != MyMoneyPrice()) // if ancient currency is added... file->addPrice(ancientCurrencies[currency]); // ...we want to add last known exchange rate as well } ft.commit(); - ui->m_removeUnusedCurrencyButton->setDisabled(file->currencyList().count() <= 1); - } - delete m_availableCurrencyDlg; -} - -void KCurrencyEditDlg::removeCurrency(const removalModeE& mode) -{ - MyMoneyFile* file = MyMoneyFile::instance(); - MyMoneyFileTransaction ft; - QBitArray skip((int)eStorage::Reference::Count); - skip.fill(false); // check reference to all... - skip.setBit((int)eStorage::Reference::Price); // ...except price - - QTreeWidgetItemIterator it (ui->m_currencyList); // iterate over whole tree - if (mode == RemoveUnused) { - while (*it) { - MyMoneySecurity currency = (*it)->data(0, Qt::UserRole).value(); - if (file->baseCurrency() != currency && !file->isReferenced(currency, skip)) - KMyMoneyUtils::deleteSecurity(currency, this); - ++it; - } - } else if (mode == RemoveSelected) { - QList currencyRows = ui->m_currencyList->selectedItems(); - foreach(auto currencyRow, currencyRows) { - MyMoneySecurity currency = currencyRow->data(0, Qt::UserRole).value(); - if (file->baseCurrency() != currency && !file->isReferenced(currency, skip)) - KMyMoneyUtils::deleteSecurity(currency, this); - } + d->ui->m_removeUnusedCurrencyButton->setDisabled(file->currencyList().count() <= 1); } - ft.commit(); - ui->m_removeUnusedCurrencyButton->setDisabled(file->currencyList().count() <= 1); + delete d->m_availableCurrencyDlg; } void KCurrencyEditDlg::slotRemoveCurrency() { - removeCurrency(RemoveSelected); + Q_D(KCurrencyEditDlg); + d->removeCurrency(KCurrencyEditDlgPrivate::RemoveSelected); } void KCurrencyEditDlg::slotRemoveUnusedCurrency() { - removeCurrency(RemoveUnused); + Q_D(KCurrencyEditDlg); + d->removeCurrency(KCurrencyEditDlgPrivate::RemoveUnused); } void KCurrencyEditDlg::slotEditCurrency() { - MyMoneySecurity currency = ui->m_currencyList->currentItem()->data(0, Qt::UserRole).value(); - m_currencyEditorDlg = new KCurrencyEditorDlg(currency); // create new dialog for editing currency - if (m_currencyEditorDlg->exec() != QDialog::Rejected) { - MyMoneyFile* file = MyMoneyFile::instance(); + Q_D(KCurrencyEditDlg); + MyMoneySecurity currency = d->ui->m_currencyList->currentItem()->data(0, Qt::UserRole).value(); + d->m_currencyEditorDlg = new KCurrencyEditorDlg(currency); // create new dialog for editing currency + if (d->m_currencyEditorDlg->exec() != QDialog::Rejected) { + auto file = MyMoneyFile::instance(); MyMoneyFileTransaction ft; - currency.setPricePrecision(m_currencyEditorDlg->ui->m_pricePrecision->value()); + currency.setPricePrecision(d->m_currencyEditorDlg->ui->m_pricePrecision->value()); try { file->modifyCurrency(currency); ft.commit(); } catch (const MyMoneyException &e) { qDebug("%s", qPrintable(e.what())); } } - delete m_currencyEditorDlg; + delete d->m_currencyEditorDlg; } diff --git a/kmymoney/dialogs/kcurrencyeditdlg.h b/kmymoney/dialogs/kcurrencyeditdlg.h index 4ce79a3e8..34210343f 100644 --- a/kmymoney/dialogs/kcurrencyeditdlg.h +++ b/kmymoney/dialogs/kcurrencyeditdlg.h @@ -1,103 +1,90 @@ /*************************************************************************** kcurrencyeditdlg.h - description ------------------- begin : Wed Mar 24 2004 copyright : (C) 2000-2004 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio Alvaro Soliverez (C) 2017 Ł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. * * * ***************************************************************************/ #ifndef KCURRENCYEDITDLG_H #define KCURRENCYEDITDLG_H // ---------------------------------------------------------------------------- // QT Includes // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes -#include "mymoneysecurity.h" - -namespace Ui -{ -class KCurrencyEditDlg; -} - class QTreeWidgetItem; class KAvailableCurrencyDlg; class KCurrencyEditorDlg; class KTreeWidgetSearchLineWidget; +class MyMoneySecurity; /** * @author Thomas Baumgart */ +class KCurrencyEditDlgPrivate; class KCurrencyEditDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KCurrencyEditDlg) + public: - KCurrencyEditDlg(QWidget *parent = 0); + explicit KCurrencyEditDlg(QWidget *parent = nullptr); ~KCurrencyEditDlg(); - Ui::KCurrencyEditDlg* ui; - public slots: void slotSelectCurrency(const QString& id); -protected: - - protected slots: - void slotSelectCurrency(QTreeWidgetItem *); + void slotSelectCurrency(QTreeWidgetItem *citem, QTreeWidgetItem *pitem); + void slotSelectCurrency(QTreeWidgetItem *item); void slotItemSelectionChanged(); void slotStartRename(); void slotOpenContextMenu(const QPoint& p); void slotLoadCurrencies(); - void slotUpdateCurrency(QTreeWidgetItem *item); + void slotUpdateCurrency(QTreeWidgetItem* citem, int column); + void slotUpdateCurrency(QTreeWidgetItem *citem, QTreeWidgetItem *pitem); private slots: void timerDone(); void slotSelectBaseCurrency(); void slotAddCurrency(); void slotRemoveCurrency(); void slotRemoveUnusedCurrency(); void slotEditCurrency(); signals: void selectObject(const MyMoneySecurity& currency); void openContextMenu(const MyMoneySecurity& currency); void updateCurrency(const QString ¤cyId, const QString& currencyName, const QString& currencyTradingSymbol); void selectBaseCurrency(const MyMoneySecurity& currency); private: - typedef enum:int { RemoveSelected, RemoveUnused} removalModeE; - KAvailableCurrencyDlg* m_availableCurrencyDlg; - KCurrencyEditorDlg* m_currencyEditorDlg; - MyMoneySecurity m_currency; - /** - * Search widget for the list - */ - KTreeWidgetSearchLineWidget* m_searchWidget; - void removeCurrency(const removalModeE& mode); + KCurrencyEditDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KCurrencyEditDlg) }; #endif diff --git a/kmymoney/dialogs/kcurrencyeditordlg.h b/kmymoney/dialogs/kcurrencyeditordlg.h index d7b063409..4b3ce838d 100644 --- a/kmymoney/dialogs/kcurrencyeditordlg.h +++ b/kmymoney/dialogs/kcurrencyeditordlg.h @@ -1,51 +1,51 @@ /*************************************************************************** kcurrencyeditordlg.h - description ------------------- begin : Sat Apr 09 2017 copyright : (C) 2017 Ł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. * * * ***************************************************************************/ #ifndef KCURRENCYEDITORDLG_H #define KCURRENCYEDITORDLG_H // ---------------------------------------------------------------------------- // QT Includes // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes namespace Ui { class KCurrencyEditorDlg; } class MyMoneySecurity; class KCurrencyEditorDlg : public QDialog { Q_OBJECT public: - KCurrencyEditorDlg(MyMoneySecurity ¤cy, QWidget *parent = 0); + KCurrencyEditorDlg(MyMoneySecurity ¤cy, QWidget *parent = nullptr); ~KCurrencyEditorDlg(); Ui::KCurrencyEditorDlg* ui; protected slots: void loadCurrency(MyMoneySecurity& currency); }; #endif diff --git a/kmymoney/dialogs/keditequityentrydecl.ui b/kmymoney/dialogs/keditequityentry.ui similarity index 99% rename from kmymoney/dialogs/keditequityentrydecl.ui rename to kmymoney/dialogs/keditequityentry.ui index 5fb263065..0a5aa7799 100644 --- a/kmymoney/dialogs/keditequityentrydecl.ui +++ b/kmymoney/dialogs/keditequityentry.ui @@ -1,271 +1,271 @@ Kevin Tambascio - KEditEquityEntryDecl - + KEditEquityEntry + 0 0 380 482 Edit Equity true Stock Mutual Fund Bond Smallest fraction: false 1 5 0 0 1 / Qt::AlignVCenter|Qt::AlignRight false Investment Type: false Equity Name: false Market Symbol: false Price History 21 21 QSizePolicy::Expanding Qt::Vertical Add Edit Remove 21 21 QSizePolicy::Expanding Qt::Vertical 238 21 QSizePolicy::Expanding Qt::Horizontal OK Cancel kMyMoneyEdit QWidget
../widgets/kmymoneyedit.h
90 25 0 1 1 image0
KMyMoneyPriceView QWidget
../widgets/kmymoneypriceview.h
-1 -1 0 5 5 image1
KComboBox QComboBox
kcombobox.h
89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000000c749444154789cad55db1184200c4c180bb005eab1cd6b8112b40d4bf1bee2486ef3006fbf1c93ece605f07eece4e1a4ed42ff2b35f6e2961132e46309941952ed8f628a761a21f56217cb20b04a45fe276d97f8ffb422431ad96e62a4ee057a83131bcc38431a6d057f8eb5cb36438afcb5cded719614011e9088308374c61aa9adb0e0651b5552b4b29efaacb099312ad5da5b2d50a93124463b2adf516fbb8cbd1354a9b1b667c8a787674144f9f982bcb93635ba8cb3fd1b2616f251013403fee763fabce8bff0aa6c989d7e67440000000049454e44ae426082 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000030149444154789cb59531681b5718c77f0e377c070e3c810a3a70e0041eac51852e0a19e45134830a1d9a4c69a04bc8928e990a693a640e1d0c8642b08742321894c1507991b484c890902bb8701a047760c3bd21701fe4201dde49b6a41a32b8df72dcbbeffdbefffbbfefbd5b1b0c07cce266ebe667ae2006c3c1dada0cdc3be87d6e6c35b0d692a409d9c7ec8b20d65ae29398d19b1114e7e3de4ce98b3f5e10dc0053cf0951b4506496e1b964bf7ce6c585d9054c62d01d617ca48be0596553cf496d8f2c8b01c5f795fc93904e85ec4c01a152857a5d9175d0b2805c872080f18595ccc1499a10a225d4e2fbc2877786fe81253ab6c04c8d106e09db5d43ab0d146e5c64d1a23938fb98a185cea1c33eecfd9eba49eb427dcb201e245365f2b7b2fb5b4a3a31dcb927178afe07d86901df870fefa4842aed6f6b74ba42e52b4014d580e1eb9cbd9d94de7e4aad16d2f9be02d805f0b5e532f927a1ffcacea1777f122a8105b164a7c25faf323a5d9f1f1fd600e1e5bec59e2d4b5c7ef5209d0ad17b8b31864e57c0b3e0815ac3ee33253ab664a770ff5185d1a1cb8d2267d3e58aa1dc7d2508cbe597d0e74fdd269aaaf0f52d414c4ea3e9762c996869e42560d7a72e41c4799a2586e74f95e8d8151481fa86efbe7b3398ac58b1a2b8527589f15451ad303ac2293542ad6648a796278f13a27185e4c4754310facb98c53a79e19a3fdc1426ff28c3d7399d1f7cb25343eb96106cf83c790ce9c4f2eb831855c55485663327992eb6dc8a6259874ed700b0b793323cccb9ffa842b30d6133e3e75fea989ac15a8b16ca76b746b0b92278d919774c5b6d48a78697fb29bbcf52468742a32120909c24e899ce67beed5be2db01e22d1e9485bb620e47f9ee9e606a21bd3f5d3744c7e7c54d55e87443867d8b554515ac5db4620e8e4f62263170fd1cdee90aad7640141992891b0f367c9adfe4049bb07d3b7022bd8c687c0978f46684ee084150b65ac1fcca94591b7a90a496e4c095164fb016a2b192a497795cc0f84817aebe25f7bf70ccc54a575c555c03f78ffa5fc0570d1f0c076bff0232285a0901e2257b0000000049454e44ae426082
diff --git a/kmymoney/dialogs/keditscheduledlg.cpp b/kmymoney/dialogs/keditscheduledlg.cpp index 5e4f796dc..c83f3e396 100644 --- a/kmymoney/dialogs/keditscheduledlg.cpp +++ b/kmymoney/dialogs/keditscheduledlg.cpp @@ -1,622 +1,661 @@ /*************************************************************************** keditscheduledlg.cpp - description ------------------- begin : Mon Sep 3 2007 copyright : (C) 2007 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "keditscheduledlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include -#include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_keditscheduledlg.h" + #include "mymoneyfile.h" #include "mymoneyschedule.h" #include "mymoneytransaction.h" #include "register.h" #include "transactionform.h" #include "transaction.h" #include "transactioneditor.h" #include "kmymoneylineedit.h" #include "kmymoneydateinput.h" #include "kmymoneymvccombo.h" #include "kguiutils.h" #include "kmymoney.h" #include "mymoneyenums.h" using namespace eMyMoney; -class KEditScheduleDlg::Private +class KEditScheduleDlgPrivate { + Q_DISABLE_COPY(KEditScheduleDlgPrivate) + Q_DECLARE_PUBLIC(KEditScheduleDlg) + public: - MyMoneySchedule m_schedule; - KMyMoneyRegister::Transaction* m_item; - QWidgetList m_tabOrderWidgets; - TransactionEditor* m_editor; - kMandatoryFieldGroup* m_requiredFields; -}; + KEditScheduleDlgPrivate(KEditScheduleDlg *qq) : + q_ptr(qq), + ui(new Ui::KEditScheduleDlg) + { + } -KEditScheduleDlg::KEditScheduleDlg(const MyMoneySchedule& schedule, QWidget *parent) : - KEditScheduleDlgDecl(parent), - d(new Private) -{ - setModal(true); - d->m_schedule = schedule; - d->m_editor = 0; + ~KEditScheduleDlgPrivate() + { + delete ui; + } + + void init() + { + Q_Q(KEditScheduleDlg); + ui->setupUi(q); - KGuiItem::assign(buttonOk, KStandardGuiItem::ok()); - KGuiItem::assign(buttonCancel, KStandardGuiItem::cancel()); - KGuiItem::assign(buttonHelp, KStandardGuiItem::help()); + m_requiredFields = new kMandatoryFieldGroup(q); + m_requiredFields->setOkButton(ui->buttonBox->button(QDialogButtonBox::Ok)); // button to be enabled when all fields present - d->m_requiredFields = new kMandatoryFieldGroup(this); - d->m_requiredFields->setOkButton(buttonOk); // button to be enabled when all fields present + // make sure, we have a tabbar with the form + // insert it after the horizontal line + ui->m_paymentInformationLayout->insertWidget(2, ui->m_form->tabBar(ui->m_form->parentWidget())); - // make sure, we have a tabbar with the form - // insert it after the horizontal line - m_paymentInformationLayout->insertWidget(2, m_form->tabBar(m_form->parentWidget())); + // we never need to see the register + ui->m_register->hide(); - // we never need to see the register - m_register->hide(); + // ... setup the form ... + ui->m_form->setupForm(m_schedule.account()); - // ... setup the form ... - m_form->setupForm(d->m_schedule.account()); + // ... and the register ... + ui->m_register->clear(); - // ... and the register ... - m_register->clear(); + // ... now add the transaction to register and form ... + auto t = transaction(); + if (m_schedule.transaction().splits().isEmpty()) + m_item = KMyMoneyRegister::Register::transactionFactory(ui->m_register, t, MyMoneySplit(), 0); + else + m_item = KMyMoneyRegister::Register::transactionFactory(ui->m_register, t, + m_schedule.transaction().splits().isEmpty() ? MyMoneySplit() : m_schedule.transaction().splits().front(), 0); + ui->m_register->selectItem(m_item); + // show the account row + m_item->setShowRowInForm(0, true); + + ui->m_form->slotSetTransaction(m_item); + + // setup widget contents + ui->m_nameEdit->setText(m_schedule.name()); + + ui->m_frequencyEdit->setCurrentItem((int)m_schedule.occurrencePeriod()); + if (ui->m_frequencyEdit->currentItem() == Schedule::Occurrence::Any) + ui->m_frequencyEdit->setCurrentItem((int)Schedule::Occurrence::Monthly); + q->slotFrequencyChanged((int)ui->m_frequencyEdit->currentItem()); + ui->m_frequencyNoEdit->setValue(m_schedule.occurrenceMultiplier()); + + // load option widgets + ui->m_paymentMethodEdit->insertItem(i18n("Direct deposit"), (int)Schedule::PaymentType::DirectDeposit); + ui->m_paymentMethodEdit->insertItem(i18n("Manual deposit"), (int)Schedule::PaymentType::ManualDeposit); + ui->m_paymentMethodEdit->insertItem(i18n("Direct debit"), (int)Schedule::PaymentType::DirectDebit); + ui->m_paymentMethodEdit->insertItem(i18n("Standing order"), (int)Schedule::PaymentType::StandingOrder); + ui->m_paymentMethodEdit->insertItem(i18n("Bank transfer"), (int)Schedule::PaymentType::BankTransfer); + ui->m_paymentMethodEdit->insertItem(i18n("Write check"), (int)Schedule::PaymentType::WriteChecque); + ui->m_paymentMethodEdit->insertItem(i18nc("Other payment method", "Other"), (int)Schedule::PaymentType::Other); + + auto method = m_schedule.paymentType(); + if (method == Schedule::PaymentType::Any) + method = Schedule::PaymentType::Other; + ui->m_paymentMethodEdit->setCurrentItem((int)method); + + switch (m_schedule.weekendOption()) { + case Schedule::WeekendOption::MoveNothing: + ui->m_weekendOptionEdit->setCurrentIndex(0); + break; + case Schedule::WeekendOption::MoveBefore: + ui->m_weekendOptionEdit->setCurrentIndex(1); + break; + case Schedule::WeekendOption::MoveAfter: + ui->m_weekendOptionEdit->setCurrentIndex(2); + break; + } + ui->m_estimateEdit->setChecked(!m_schedule.isFixed()); + ui->m_lastDayInMonthEdit->setChecked(m_schedule.lastDayInMonth()); + ui->m_autoEnterEdit->setChecked(m_schedule.autoEnter()); + ui->m_endSeriesEdit->setChecked(m_schedule.willEnd()); + + ui->m_endOptionsFrame->setEnabled(m_schedule.willEnd()); + if (m_schedule.willEnd()) { + ui->m_RemainingEdit->setValue(m_schedule.transactionsRemaining()); + ui->m_FinalPaymentEdit->setDate(m_schedule.endDate()); + } - // ... now add the transaction to register and form ... - MyMoneyTransaction t = transaction(); - if (d->m_schedule.transaction().splits().isEmpty()) - d->m_item = KMyMoneyRegister::Register::transactionFactory(m_register, t, MyMoneySplit(), 0); - else - d->m_item = KMyMoneyRegister::Register::transactionFactory(m_register, t, - d->m_schedule.transaction().splits().isEmpty() ? MyMoneySplit() : d->m_schedule.transaction().splits().front(), 0); - m_register->selectItem(d->m_item); - // show the account row - d->m_item->setShowRowInForm(0, true); + q->connect(ui->m_RemainingEdit, static_cast(&QSpinBox::valueChanged), + q, &KEditScheduleDlg::slotRemainingChanged); + q->connect(ui->m_FinalPaymentEdit, &kMyMoneyDateInput::dateChanged, + q, &KEditScheduleDlg::slotEndDateChanged); + q->connect(ui->m_frequencyEdit, &KMyMoneyGeneralCombo::itemSelected, + q, &KEditScheduleDlg::slotFrequencyChanged); + q->connect(ui->m_frequencyNoEdit, static_cast(&QSpinBox::valueChanged), + q, &KEditScheduleDlg::slotOccurrenceMultiplierChanged); + q->connect(ui->buttonBox, &QDialogButtonBox::helpRequested, q, &KEditScheduleDlg::slotShowHelp); + + q->setModal(true); + // force the initial height to be as small as possible + QTimer::singleShot(0, q, SLOT(slotSetupSize())); + + // we just hide the variation field for now and enable the logic + // once we have a respective member in the MyMoneySchedule object + ui->m_variation->hide(); + } - m_form->slotSetTransaction(d->m_item); + /** + * Helper method to recalculate and update Transactions Remaining + * when other values are changed + */ + void updateTransactionsRemaining() + { + auto remain = m_schedule.transactionsRemaining(); + if (remain != ui->m_RemainingEdit->value()) { + ui->m_RemainingEdit->blockSignals(true); + ui->m_RemainingEdit->setValue(remain); + ui->m_RemainingEdit->blockSignals(false); + } + } - // setup widget contents - m_nameEdit->setText(d->m_schedule.name()); + MyMoneyTransaction transaction() const + { + auto t = m_schedule.transaction(); - m_frequencyEdit->setCurrentItem((int)d->m_schedule.occurrencePeriod()); - if (m_frequencyEdit->currentItem() == Schedule::Occurrence::Any) - m_frequencyEdit->setCurrentItem((int)Schedule::Occurrence::Monthly); - slotFrequencyChanged((int)m_frequencyEdit->currentItem()); - m_frequencyNoEdit->setValue(d->m_schedule.occurrenceMultiplier()); + if (m_editor) { + m_editor->createTransaction(t, m_schedule.transaction(), m_schedule.transaction().splits().isEmpty() ? MyMoneySplit() : m_schedule.transaction().splits().front(), false); + } - // load option widgets - m_paymentMethodEdit->insertItem(i18n("Direct deposit"), (int)Schedule::PaymentType::DirectDeposit); - m_paymentMethodEdit->insertItem(i18n("Manual deposit"), (int)Schedule::PaymentType::ManualDeposit); - m_paymentMethodEdit->insertItem(i18n("Direct debit"), (int)Schedule::PaymentType::DirectDebit); - m_paymentMethodEdit->insertItem(i18n("Standing order"), (int)Schedule::PaymentType::StandingOrder); - m_paymentMethodEdit->insertItem(i18n("Bank transfer"), (int)Schedule::PaymentType::BankTransfer); - m_paymentMethodEdit->insertItem(i18n("Write check"), (int)Schedule::PaymentType::WriteChecque); - m_paymentMethodEdit->insertItem(i18nc("Other payment method", "Other"), (int)Schedule::PaymentType::Other); - - auto method = d->m_schedule.paymentType(); - if (method == Schedule::PaymentType::Any) - method = Schedule::PaymentType::Other; - m_paymentMethodEdit->setCurrentItem((int)method); - - switch (d->m_schedule.weekendOption()) { - case Schedule::WeekendOption::MoveNothing: - m_weekendOptionEdit->setCurrentIndex(0); - break; - case Schedule::WeekendOption::MoveBefore: - m_weekendOptionEdit->setCurrentIndex(1); - break; - case Schedule::WeekendOption::MoveAfter: - m_weekendOptionEdit->setCurrentIndex(2); - break; - } - m_estimateEdit->setChecked(!d->m_schedule.isFixed()); - m_lastDayInMonthEdit->setChecked(d->m_schedule.lastDayInMonth()); - m_autoEnterEdit->setChecked(d->m_schedule.autoEnter()); - m_endSeriesEdit->setChecked(d->m_schedule.willEnd()); - - m_endOptionsFrame->setEnabled(d->m_schedule.willEnd()); - if (d->m_schedule.willEnd()) { - m_RemainingEdit->setValue(d->m_schedule.transactionsRemaining()); - m_FinalPaymentEdit->setDate(d->m_schedule.endDate()); + t.clearId(); + t.setEntryDate(QDate()); + return t; } + + KEditScheduleDlg *q_ptr; + Ui::KEditScheduleDlg *ui; + MyMoneySchedule m_schedule; + KMyMoneyRegister::Transaction* m_item; + QWidgetList m_tabOrderWidgets; + TransactionEditor* m_editor; + kMandatoryFieldGroup* m_requiredFields; +}; - connect(m_RemainingEdit, SIGNAL(valueChanged(int)), - this, SLOT(slotRemainingChanged(int))); - connect(m_FinalPaymentEdit, SIGNAL(dateChanged(QDate)), - this, SLOT(slotEndDateChanged(QDate))); - connect(m_frequencyEdit, SIGNAL(itemSelected(int)), - this, SLOT(slotFrequencyChanged(int))); - connect(m_frequencyNoEdit, SIGNAL(valueChanged(int)), - this, SLOT(slotOccurrenceMultiplierChanged(int))); - connect(buttonHelp, SIGNAL(clicked()), this, SLOT(slotShowHelp())); - - // force the initial height to be as small as possible - QTimer::singleShot(0, this, SLOT(slotSetupSize())); - - // we just hide the variation field for now and enable the logic - // once we have a respective member in the MyMoneySchedule object - m_variation->hide(); +KEditScheduleDlg::KEditScheduleDlg(const MyMoneySchedule& schedule, QWidget *parent) : + QDialog(parent), + d_ptr(new KEditScheduleDlgPrivate(this)) +{ + Q_D(KEditScheduleDlg); + d->m_schedule = schedule; + d->m_editor = 0; + d->init(); } KEditScheduleDlg::~KEditScheduleDlg() { + Q_D(KEditScheduleDlg); delete d; } void KEditScheduleDlg::slotSetupSize() { resize(width(), minimumSizeHint().height()); } TransactionEditor* KEditScheduleDlg::startEdit() { - KMyMoneyRegister::SelectedTransactions list(m_register); - TransactionEditor* editor = d->m_item->createEditor(m_form, list, QDate()); + Q_D(KEditScheduleDlg); + KMyMoneyRegister::SelectedTransactions list(d->ui->m_register); + TransactionEditor* editor = d->m_item->createEditor(d->ui->m_form, list, QDate()); // check that we use the same transaction commodity in all selected transactions // if not, we need to update this in the editor's list. The user can also bail out // of this operation which means that we have to stop editing here. if (editor && !d->m_schedule.account().id().isEmpty()) { if (!editor->fixTransactionCommodity(d->m_schedule.account())) { // if the user wants to quit, we need to destroy the editor // and bail out delete editor; editor = 0; } } if (editor) { - editor->m_scheduleInfo = m_nameEdit->text(); - connect(editor, SIGNAL(transactionDataSufficient(bool)), buttonOk, SLOT(setEnabled(bool))); - connect(editor, SIGNAL(escapePressed()), buttonCancel, SLOT(animateClick())); - connect(editor, SIGNAL(returnPressed()), buttonOk, SLOT(animateClick())); + editor->setScheduleInfo(d->ui->m_nameEdit->text()); + connect(editor, &TransactionEditor::transactionDataSufficient, d->ui->buttonBox->button(QDialogButtonBox::Ok), &QWidget::setEnabled); + connect(editor, &TransactionEditor::escapePressed, d->ui->buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::animateClick); + connect(editor, &TransactionEditor::returnPressed, d->ui->buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::animateClick); - connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), editor, SLOT(slotReloadEditWidgets())); + connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, editor, &TransactionEditor::slotReloadEditWidgets); // connect(editor, SIGNAL(finishEdit(KMyMoneyRegister::SelectedTransactions)), this, SLOT(slotLeaveEditMode(KMyMoneyRegister::SelectedTransactions))); - connect(editor, SIGNAL(createPayee(QString,QString&)), kmymoney, SLOT(slotPayeeNew(QString,QString&))); - connect(editor, SIGNAL(createTag(QString,QString&)), kmymoney, SLOT(slotTagNew(QString,QString&))); - connect(editor, SIGNAL(createCategory(MyMoneyAccount&,MyMoneyAccount)), kmymoney, SLOT(slotCategoryNew(MyMoneyAccount&,MyMoneyAccount))); - connect(editor, SIGNAL(createSecurity(MyMoneyAccount&,MyMoneyAccount)), kmymoney, SLOT(slotInvestmentNew(MyMoneyAccount&,MyMoneyAccount))); - connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), editor, SLOT(slotReloadEditWidgets())); + connect(editor, &TransactionEditor::createPayee, kmymoney, static_cast(&KMyMoneyApp::slotPayeeNew)); + connect(editor, &TransactionEditor::createTag, kmymoney, static_cast(&KMyMoneyApp::slotTagNew)); + connect(editor, &TransactionEditor::createCategory, kmymoney, static_cast(&KMyMoneyApp::slotCategoryNew)); + connect(editor, &TransactionEditor::createSecurity, kmymoney, static_cast(&KMyMoneyApp::slotInvestmentNew)); + connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, editor, &TransactionEditor::slotReloadEditWidgets); // create the widgets, place them in the parent and load them with data // setup tab order d->m_tabOrderWidgets.clear(); KMyMoneyRegister::Action action = KMyMoneyRegister::ActionWithdrawal; switch (d->m_schedule.type()) { case Schedule::Type::Deposit: action = KMyMoneyRegister::ActionDeposit; break; case Schedule::Type::Bill: action = KMyMoneyRegister::ActionWithdrawal; - editor->m_paymentMethod = d->m_schedule.paymentType(); + editor->setPaymentMethod(d->m_schedule.paymentType()); break; case Schedule::Type::Transfer: action = KMyMoneyRegister::ActionTransfer; break; default: // if we end up here, we don't have a known schedule type (yet). in this case, we just glimpse // into the transaction and determine the type. in case we don't have a transaction with splits // we stick with the default action already set up if (d->m_schedule.transaction().splits().count() > 0) { auto isDeposit = false; auto isTransfer = false; - foreach (const auto split, d->m_schedule.transaction().splits()) { + auto splits = d->m_schedule.transaction().splits(); + foreach (const auto split, splits) { if (split.accountId() == d->m_schedule.account().id()) { isDeposit = !(split.shares().isNegative()); } else { auto acc = MyMoneyFile::instance()->account(split.accountId()); if (acc.isAssetLiability() && d->m_schedule.transaction().splits().count() == 2) { isTransfer = true; } } } if (isTransfer) action = KMyMoneyRegister::ActionTransfer; else if (isDeposit) action = KMyMoneyRegister::ActionDeposit; } break; } editor->setup(d->m_tabOrderWidgets, d->m_schedule.account(), action); // if it's not a check, then we need to clear // a possibly assigned check number if (d->m_schedule.paymentType() != Schedule::PaymentType::WriteChecque) { QWidget* w = editor->haveWidget("number"); if (w) dynamic_cast(w)->loadText(QString()); } Q_ASSERT(!d->m_tabOrderWidgets.isEmpty()); - d->m_tabOrderWidgets.push_front(m_paymentMethodEdit); + d->m_tabOrderWidgets.push_front(d->ui->m_paymentMethodEdit); // editor->setup() leaves the tabbar as the last widget in the stack, but we // need it as first here. So we move it around. QWidget* w = editor->haveWidget("tabbar"); if (w) { int idx = d->m_tabOrderWidgets.indexOf(w); if (idx != -1) { d->m_tabOrderWidgets.removeAt(idx); d->m_tabOrderWidgets.push_front(w); } } // don't forget our three buttons and additional widgets // make sure to use the correct order - d->m_tabOrderWidgets.push_front(m_frequencyEdit); - d->m_tabOrderWidgets.push_front(m_frequencyNoEdit); - d->m_tabOrderWidgets.push_front(m_nameEdit); - - d->m_tabOrderWidgets.append(m_weekendOptionEdit); - d->m_tabOrderWidgets.append(m_estimateEdit); - d->m_tabOrderWidgets.append(m_variation); - d->m_tabOrderWidgets.append(m_lastDayInMonthEdit); - d->m_tabOrderWidgets.append(m_autoEnterEdit); - d->m_tabOrderWidgets.append(m_endSeriesEdit); - d->m_tabOrderWidgets.append(m_RemainingEdit); - d->m_tabOrderWidgets.append(m_FinalPaymentEdit); - - d->m_tabOrderWidgets.append(buttonOk); - d->m_tabOrderWidgets.append(buttonCancel); - d->m_tabOrderWidgets.append(buttonHelp); - for (int i = 0; i < d->m_tabOrderWidgets.size(); ++i) { + d->m_tabOrderWidgets.push_front(d->ui->m_frequencyEdit); + d->m_tabOrderWidgets.push_front(d->ui->m_frequencyNoEdit); + d->m_tabOrderWidgets.push_front(d->ui->m_nameEdit); + + d->m_tabOrderWidgets.append(d->ui->m_weekendOptionEdit); + d->m_tabOrderWidgets.append(d->ui->m_estimateEdit); + d->m_tabOrderWidgets.append(d->ui->m_variation); + d->m_tabOrderWidgets.append(d->ui->m_lastDayInMonthEdit); + d->m_tabOrderWidgets.append(d->ui->m_autoEnterEdit); + d->m_tabOrderWidgets.append(d->ui->m_endSeriesEdit); + d->m_tabOrderWidgets.append(d->ui->m_RemainingEdit); + d->m_tabOrderWidgets.append(d->ui->m_FinalPaymentEdit); + + d->m_tabOrderWidgets.append(d->ui->buttonBox->button(QDialogButtonBox::Ok)); + d->m_tabOrderWidgets.append(d->ui->buttonBox->button(QDialogButtonBox::Cancel)); + d->m_tabOrderWidgets.append(d->ui->buttonBox->button(QDialogButtonBox::Help)); + for (auto i = 0; i < d->m_tabOrderWidgets.size(); ++i) { QWidget* w = d->m_tabOrderWidgets.at(i); if (w) { w->installEventFilter(this); w->installEventFilter(editor); } } // connect the postdate modification signal to our update routine kMyMoneyDateInput* dateEdit = dynamic_cast(editor->haveWidget("postdate")); if (dateEdit) - connect(dateEdit, SIGNAL(dateChanged(QDate)), this, SLOT(slotPostDateChanged(QDate))); + connect(dateEdit, &kMyMoneyDateInput::dateChanged, this, &KEditScheduleDlg::slotPostDateChanged); - m_nameEdit->setFocus(); + d->ui->m_nameEdit->setFocus(); // add the required fields to the mandatory group - d->m_requiredFields->add(m_nameEdit); + d->m_requiredFields->add(d->ui->m_nameEdit); d->m_requiredFields->add(editor->haveWidget("account")); d->m_requiredFields->add(editor->haveWidget("category")); d->m_requiredFields->add(editor->haveWidget("amount")); // fix labels QLabel* label = dynamic_cast(editor->haveWidget("date-label")); if (label) { label->setText(i18n("Next due date")); } d->m_editor = editor; slotSetPaymentMethod((int)d->m_schedule.paymentType()); - connect(m_paymentMethodEdit, SIGNAL(itemSelected(int)), this, SLOT(slotSetPaymentMethod(int))); - connect(editor, SIGNAL(operationTypeChanged(int)), this, SLOT(slotFilterPaymentType(int))); + connect(d->ui->m_paymentMethodEdit, &KMyMoneyGeneralCombo::itemSelected, this, &KEditScheduleDlg::slotSetPaymentMethod); + connect(editor, &TransactionEditor::operationTypeChanged, this, &KEditScheduleDlg::slotFilterPaymentType); } return editor; } void KEditScheduleDlg::accept() { + Q_D(KEditScheduleDlg); // Force the focus to be on the OK button. This will trigger creation // of any unknown objects (payees, categories etc.) - buttonOk->setFocus(); + d->ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); // only accept if the button is really still enabled. We could end // up here, if the user filled all fields, the focus is on the category // field, but the category is not yet existent. When the user presses the // OK button in this context, he will be asked if he wants to create // the category or not. In case he decides no, we end up here with no // category filled in, so we don't run through the final acceptance. - if (buttonOk->isEnabled()) - KEditScheduleDlgDecl::accept(); + if (d->ui->buttonBox->button(QDialogButtonBox::Ok)->isEnabled()) + QDialog::accept(); } -const MyMoneySchedule& KEditScheduleDlg::schedule() const +const MyMoneySchedule& KEditScheduleDlg::schedule() { + Q_D(KEditScheduleDlg); if (d->m_editor) { - MyMoneyTransaction t = transaction(); + auto t = d->transaction(); if (d->m_schedule.nextDueDate() != t.postDate()) { d->m_schedule.setNextDueDate(t.postDate()); d->m_schedule.setStartDate(t.postDate()); } d->m_schedule.setTransaction(t); - d->m_schedule.setName(m_nameEdit->text()); - d->m_schedule.setFixed(!m_estimateEdit->isChecked()); - d->m_schedule.setOccurrencePeriod(static_cast(m_frequencyEdit->currentItem())); - d->m_schedule.setOccurrenceMultiplier(m_frequencyNoEdit->value()); + d->m_schedule.setName(d->ui->m_nameEdit->text()); + d->m_schedule.setFixed(!d->ui->m_estimateEdit->isChecked()); + d->m_schedule.setOccurrencePeriod(static_cast(d->ui->m_frequencyEdit->currentItem())); + d->m_schedule.setOccurrenceMultiplier(d->ui->m_frequencyNoEdit->value()); - switch (m_weekendOptionEdit->currentIndex()) { + switch (d->ui->m_weekendOptionEdit->currentIndex()) { case 0: d->m_schedule.setWeekendOption(Schedule::WeekendOption::MoveNothing); break; case 1: d->m_schedule.setWeekendOption(Schedule::WeekendOption::MoveBefore); break; case 2: d->m_schedule.setWeekendOption(Schedule::WeekendOption::MoveAfter); break; } d->m_schedule.setType(Schedule::Type::Bill); KMyMoneyTransactionForm::TabBar* tabbar = dynamic_cast(d->m_editor->haveWidget("tabbar")); if (tabbar) { switch (static_cast(tabbar->currentIndex())) { case KMyMoneyRegister::ActionDeposit: d->m_schedule.setType(Schedule::Type::Deposit); break; default: case KMyMoneyRegister::ActionWithdrawal: d->m_schedule.setType(Schedule::Type::Bill); break; case KMyMoneyRegister::ActionTransfer: d->m_schedule.setType(Schedule::Type::Transfer); break; } } else { qDebug("No tabbar found in KEditScheduleDlg::schedule(). Defaulting type to BILL"); } - if(m_lastDayInMonthEdit->isEnabled()) - d->m_schedule.setLastDayInMonth(m_lastDayInMonthEdit->isChecked()); + if(d->ui->m_lastDayInMonthEdit->isEnabled()) + d->m_schedule.setLastDayInMonth(d->ui->m_lastDayInMonthEdit->isChecked()); else d->m_schedule.setLastDayInMonth(false); - d->m_schedule.setAutoEnter(m_autoEnterEdit->isChecked()); - d->m_schedule.setPaymentType(static_cast(m_paymentMethodEdit->currentItem())); - if (m_endSeriesEdit->isEnabled() && m_endSeriesEdit->isChecked()) { - d->m_schedule.setEndDate(m_FinalPaymentEdit->date()); + d->m_schedule.setAutoEnter(d->ui->m_autoEnterEdit->isChecked()); + d->m_schedule.setPaymentType(static_cast(d->ui->m_paymentMethodEdit->currentItem())); + if (d->ui->m_endSeriesEdit->isEnabled() && d->ui->m_endSeriesEdit->isChecked()) { + d->m_schedule.setEndDate(d->ui->m_FinalPaymentEdit->date()); } else { d->m_schedule.setEndDate(QDate()); } } return d->m_schedule; } -MyMoneyTransaction KEditScheduleDlg::transaction() const -{ - MyMoneyTransaction t = d->m_schedule.transaction(); - - if (d->m_editor) { - d->m_editor->createTransaction(t, d->m_schedule.transaction(), d->m_schedule.transaction().splits().isEmpty() ? MyMoneySplit() : d->m_schedule.transaction().splits().front(), false); - } - - t.clearId(); - t.setEntryDate(QDate()); - return t; -} - bool KEditScheduleDlg::focusNextPrevChild(bool next) { - bool rc = false; - QWidget *w = 0; + Q_D(KEditScheduleDlg); + auto rc = false; - w = qApp->focusWidget(); - int currentWidgetIndex = d->m_tabOrderWidgets.indexOf(w); + auto w = qApp->focusWidget(); + auto currentWidgetIndex = d->m_tabOrderWidgets.indexOf(w); while (w && currentWidgetIndex == -1) { // qDebug("'%s' not in list, use parent", qPrintable(w->objectName())); w = w->parentWidget(); currentWidgetIndex = d->m_tabOrderWidgets.indexOf(w); } if (currentWidgetIndex != -1) { do { // if(w) qDebug("tab order is at '%s (%d/%d)'", qPrintable(w->objectName()), currentWidgetIndex, d->m_tabOrderWidgets.size()); currentWidgetIndex += next ? 1 : -1; if (currentWidgetIndex < 0) currentWidgetIndex = d->m_tabOrderWidgets.size() - 1; else if (currentWidgetIndex >= d->m_tabOrderWidgets.size()) currentWidgetIndex = 0; w = d->m_tabOrderWidgets[currentWidgetIndex]; // qDebug("currentWidgetIndex = %d, w = %p", currentWidgetIndex, w); if (((w->focusPolicy() & Qt::TabFocus) == Qt::TabFocus) && w->isVisible() && w->isEnabled()) { // qDebug("Selecting '%s' as focus", qPrintable(w->objectName())); w->setFocus(); rc = true; } } while (rc == false); } return rc; } void KEditScheduleDlg::resizeEvent(QResizeEvent* ev) { - m_register->resize(KMyMoneyRegister::DetailColumn); - m_form->resize(KMyMoneyTransactionForm::ValueColumn1); - KEditScheduleDlgDecl::resizeEvent(ev); + Q_D(KEditScheduleDlg); + d->ui->m_register->resize(KMyMoneyRegister::DetailColumn); + d->ui->m_form->resize(KMyMoneyTransactionForm::ValueColumn1); + QDialog::resizeEvent(ev); } void KEditScheduleDlg::slotRemainingChanged(int value) { + Q_D(KEditScheduleDlg); // Make sure the required fields are set - kMyMoneyDateInput* dateEdit = dynamic_cast(d->m_editor->haveWidget("postdate")); + auto dateEdit = dynamic_cast(d->m_editor->haveWidget("postdate")); d->m_schedule.setNextDueDate(dateEdit->date()); - d->m_schedule.setOccurrencePeriod(static_cast(m_frequencyEdit->currentItem())); - d->m_schedule.setOccurrenceMultiplier(m_frequencyNoEdit->value()); + d->m_schedule.setOccurrencePeriod(static_cast(d->ui->m_frequencyEdit->currentItem())); + d->m_schedule.setOccurrenceMultiplier(d->ui->m_frequencyNoEdit->value()); if (d->m_schedule.transactionsRemaining() != value) { - m_FinalPaymentEdit->blockSignals(true); - m_FinalPaymentEdit->setDate(d->m_schedule.dateAfter(value)); - m_FinalPaymentEdit->blockSignals(false); + d->ui->m_FinalPaymentEdit->blockSignals(true); + d->ui->m_FinalPaymentEdit->setDate(d->m_schedule.dateAfter(value)); + d->ui->m_FinalPaymentEdit->blockSignals(false); } } void KEditScheduleDlg::slotEndDateChanged(const QDate& date) { + Q_D(KEditScheduleDlg); // Make sure the required fields are set - kMyMoneyDateInput* dateEdit = dynamic_cast(d->m_editor->haveWidget("postdate")); + auto dateEdit = dynamic_cast(d->m_editor->haveWidget("postdate")); d->m_schedule.setNextDueDate(dateEdit->date()); - d->m_schedule.setOccurrencePeriod(static_cast(m_frequencyEdit->currentItem())); - d->m_schedule.setOccurrenceMultiplier(m_frequencyNoEdit->value()); + d->m_schedule.setOccurrencePeriod(static_cast(d->ui->m_frequencyEdit->currentItem())); + d->m_schedule.setOccurrenceMultiplier(d->ui->m_frequencyNoEdit->value()); if (d->m_schedule.endDate() != date) { d->m_schedule.setEndDate(date); - updateTransactionsRemaining(); + d->updateTransactionsRemaining(); } } void KEditScheduleDlg::slotPostDateChanged(const QDate& date) { + Q_D(KEditScheduleDlg); if (d->m_schedule.nextDueDate() != date) { - if (m_endOptionsFrame->isEnabled()) { + if (d->ui->m_endOptionsFrame->isEnabled()) { d->m_schedule.setNextDueDate(date); - d->m_schedule.setOccurrenceMultiplier(m_frequencyNoEdit->value()); - d->m_schedule.setOccurrencePeriod(static_cast(m_frequencyEdit->currentItem())); - d->m_schedule.setEndDate(m_FinalPaymentEdit->date()); - updateTransactionsRemaining(); + d->m_schedule.setOccurrenceMultiplier(d->ui->m_frequencyNoEdit->value()); + d->m_schedule.setOccurrencePeriod(static_cast(d->ui->m_frequencyEdit->currentItem())); + d->m_schedule.setEndDate(d->ui->m_FinalPaymentEdit->date()); + d->updateTransactionsRemaining(); } } } void KEditScheduleDlg::slotSetPaymentMethod(int item) { - kMyMoneyLineEdit* dateEdit = dynamic_cast(d->m_editor->haveWidget("number")); + Q_D(KEditScheduleDlg); + auto dateEdit = dynamic_cast(d->m_editor->haveWidget("number")); if (dateEdit) { dateEdit->setVisible(item == (int)Schedule::PaymentType::WriteChecque); // hiding the label does not work, because the label underneath will shine // through. So we either write the label or a blank QLabel* label = dynamic_cast(d->m_editor->haveWidget("number-label")); if (label) { label->setText((item == (int)Schedule::PaymentType::WriteChecque) ? i18n("Number") : " "); } } } void KEditScheduleDlg::slotFrequencyChanged(int item) { - m_endSeriesEdit->setEnabled(item != (int)Schedule::Occurrence::Once); - bool isEndSeries = m_endSeriesEdit->isChecked(); + Q_D(KEditScheduleDlg); + d->ui->m_endSeriesEdit->setEnabled(item != (int)Schedule::Occurrence::Once); + bool isEndSeries = d->ui->m_endSeriesEdit->isChecked(); if (isEndSeries) - m_endOptionsFrame->setEnabled(item != (int)Schedule::Occurrence::Once); + d->ui->m_endOptionsFrame->setEnabled(item != (int)Schedule::Occurrence::Once); switch (item) { case (int)Schedule::Occurrence::Daily: case (int)Schedule::Occurrence::Weekly: - m_frequencyNoEdit->setEnabled(true); - m_lastDayInMonthEdit->setEnabled(false); + d->ui->m_frequencyNoEdit->setEnabled(true); + d->ui->m_lastDayInMonthEdit->setEnabled(false); break; case (int)Schedule::Occurrence::EveryHalfMonth: case (int)Schedule::Occurrence::Monthly: case (int)Schedule::Occurrence::Yearly: // Supports Frequency Number - m_frequencyNoEdit->setEnabled(true); - m_lastDayInMonthEdit->setEnabled(true); + d->ui->m_frequencyNoEdit->setEnabled(true); + d->ui->m_lastDayInMonthEdit->setEnabled(true); break; default: // Multiplier is always 1 - m_frequencyNoEdit->setEnabled(false); - m_frequencyNoEdit->setValue(1); - m_lastDayInMonthEdit->setEnabled(true); + d->ui->m_frequencyNoEdit->setEnabled(false); + d->ui->m_frequencyNoEdit->setValue(1); + d->ui->m_lastDayInMonthEdit->setEnabled(true); break; } if (isEndSeries && (item != (int)Schedule::Occurrence::Once)) { // Changing the frequency changes the number // of remaining transactions kMyMoneyDateInput* dateEdit = dynamic_cast(d->m_editor->haveWidget("postdate")); d->m_schedule.setNextDueDate(dateEdit->date()); - d->m_schedule.setOccurrenceMultiplier(m_frequencyNoEdit->value()); + d->m_schedule.setOccurrenceMultiplier(d->ui->m_frequencyNoEdit->value()); d->m_schedule.setOccurrencePeriod(static_cast(item)); - d->m_schedule.setEndDate(m_FinalPaymentEdit->date()); - updateTransactionsRemaining(); + d->m_schedule.setEndDate(d->ui->m_FinalPaymentEdit->date()); + d->updateTransactionsRemaining(); } } void KEditScheduleDlg::slotOccurrenceMultiplierChanged(int multiplier) { + Q_D(KEditScheduleDlg); // Make sure the required fields are set - int oldOccurrenceMultiplier = d->m_schedule.occurrenceMultiplier(); + auto oldOccurrenceMultiplier = d->m_schedule.occurrenceMultiplier(); if (multiplier != oldOccurrenceMultiplier) { - if (m_endOptionsFrame->isEnabled()) { + if (d->ui->m_endOptionsFrame->isEnabled()) { kMyMoneyDateInput* dateEdit = dynamic_cast(d->m_editor->haveWidget("postdate")); d->m_schedule.setNextDueDate(dateEdit->date()); d->m_schedule.setOccurrenceMultiplier(multiplier); - d->m_schedule.setOccurrencePeriod(static_cast(m_frequencyEdit->currentItem())); - d->m_schedule.setEndDate(m_FinalPaymentEdit->date()); - updateTransactionsRemaining(); + d->m_schedule.setOccurrencePeriod(static_cast(d->ui->m_frequencyEdit->currentItem())); + d->m_schedule.setEndDate(d->ui->m_FinalPaymentEdit->date()); + d->updateTransactionsRemaining(); } } } -void KEditScheduleDlg::updateTransactionsRemaining() -{ - int remain = d->m_schedule.transactionsRemaining(); - if (remain != m_RemainingEdit->value()) { - m_RemainingEdit->blockSignals(true); - m_RemainingEdit->setValue(remain); - m_RemainingEdit->blockSignals(false); - } -} - void KEditScheduleDlg::slotShowHelp() { KHelpClient::invokeHelp("details.schedules.intro"); } void KEditScheduleDlg::slotFilterPaymentType(int index) { + Q_D(KEditScheduleDlg); //save selected item to reload if possible - int selectedId = m_paymentMethodEdit->itemData(m_paymentMethodEdit->currentIndex(), Qt::UserRole).toInt(); + auto selectedId = d->ui->m_paymentMethodEdit->itemData(d->ui->m_paymentMethodEdit->currentIndex(), Qt::UserRole).toInt(); //clear and reload the widget with the correct items - m_paymentMethodEdit->clear(); + d->ui->m_paymentMethodEdit->clear(); // load option widgets KMyMoneyRegister::Action action = static_cast(index); if (action != KMyMoneyRegister::ActionWithdrawal) { - m_paymentMethodEdit->insertItem(i18n("Direct deposit"), (int)Schedule::PaymentType::DirectDeposit); - m_paymentMethodEdit->insertItem(i18n("Manual deposit"), (int)Schedule::PaymentType::ManualDeposit); + d->ui->m_paymentMethodEdit->insertItem(i18n("Direct deposit"), (int)Schedule::PaymentType::DirectDeposit); + d->ui->m_paymentMethodEdit->insertItem(i18n("Manual deposit"), (int)Schedule::PaymentType::ManualDeposit); } if (action != KMyMoneyRegister::ActionDeposit) { - m_paymentMethodEdit->insertItem(i18n("Direct debit"), (int)Schedule::PaymentType::DirectDebit); - m_paymentMethodEdit->insertItem(i18n("Write check"), (int)Schedule::PaymentType::WriteChecque); + d->ui->m_paymentMethodEdit->insertItem(i18n("Direct debit"), (int)Schedule::PaymentType::DirectDebit); + d->ui->m_paymentMethodEdit->insertItem(i18n("Write check"), (int)Schedule::PaymentType::WriteChecque); } - m_paymentMethodEdit->insertItem(i18n("Standing order"), (int)Schedule::PaymentType::StandingOrder); - m_paymentMethodEdit->insertItem(i18n("Bank transfer"), (int)Schedule::PaymentType::BankTransfer); - m_paymentMethodEdit->insertItem(i18nc("Other payment method", "Other"), (int)Schedule::PaymentType::Other); + d->ui->m_paymentMethodEdit->insertItem(i18n("Standing order"), (int)Schedule::PaymentType::StandingOrder); + d->ui->m_paymentMethodEdit->insertItem(i18n("Bank transfer"), (int)Schedule::PaymentType::BankTransfer); + d->ui->m_paymentMethodEdit->insertItem(i18nc("Other payment method", "Other"), (int)Schedule::PaymentType::Other); - int newIndex = m_paymentMethodEdit->findData(QVariant(selectedId), Qt::UserRole, Qt::MatchExactly); + auto newIndex = d->ui->m_paymentMethodEdit->findData(QVariant(selectedId), Qt::UserRole, Qt::MatchExactly); if (newIndex > -1) { - m_paymentMethodEdit->setCurrentIndex(newIndex); + d->ui->m_paymentMethodEdit->setCurrentIndex(newIndex); } else { - m_paymentMethodEdit->setCurrentIndex(0); + d->ui->m_paymentMethodEdit->setCurrentIndex(0); } } diff --git a/kmymoney/dialogs/keditscheduledlg.h b/kmymoney/dialogs/keditscheduledlg.h index 57a512382..be4def9df 100644 --- a/kmymoney/dialogs/keditscheduledlg.h +++ b/kmymoney/dialogs/keditscheduledlg.h @@ -1,112 +1,92 @@ /*************************************************************************** keditscheduledlg.h - description ------------------- begin : Mon Sep 3 2007 copyright : (C) 2007 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KEDITSCHEDULEDLG_H #define KEDITSCHEDULEDLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_keditscheduledlgdecl.h" - class MyMoneySchedule; class MyMoneyTransaction; class TransactionEditor; /** * @author Thomas Baumgart */ -class KEditScheduleDlgDecl : public QDialog, public Ui::KEditScheduleDlgDecl -{ -public: - explicit KEditScheduleDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; -class KEditScheduleDlg : public KEditScheduleDlgDecl + +class KEditScheduleDlgPrivate; +class KEditScheduleDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KEditScheduleDlg) + public: - /** - * Standard QWidget constructor. - **/ - explicit KEditScheduleDlg(const MyMoneySchedule& schedule, QWidget *parent = 0); - - /** - * Standard destructor. - **/ + explicit KEditScheduleDlg(const MyMoneySchedule& schedule, QWidget *parent = nullptr); ~KEditScheduleDlg(); TransactionEditor* startEdit(); /** * Returns the edited schedule. * * @return MyMoneySchedule The schedule details. **/ - const MyMoneySchedule& schedule() const; + const MyMoneySchedule& schedule(); protected: - MyMoneyTransaction transaction() const; /** * This method adjusts @a _date according to the rules specified by * the schedule's weekend option. */ QDate adjustDate(const QDate& _date) const; /// Overridden for internal reasons. No API changes. - bool focusNextPrevChild(bool next); + bool focusNextPrevChild(bool next) override; /// Overridden for internal reasons. No API changes. - void resizeEvent(QResizeEvent* ev); + void resizeEvent(QResizeEvent* ev) override; private slots: void slotSetupSize(); void slotRemainingChanged(int); void slotEndDateChanged(const QDate& date); void slotPostDateChanged(const QDate& date); void slotSetPaymentMethod(int); void slotFrequencyChanged(int item); void slotShowHelp(); void slotOccurrenceMultiplierChanged(int mult); void slotFilterPaymentType(int index); /// Overridden for internal reasons. No API changes. - void accept(); + void accept() override; private: - /** - * Helper method to recalculate and update Transactions Remaining - * when other values are changed - */ - void updateTransactionsRemaining(); - - /// \internal d-pointer class. - class Private; - /// \internal d-pointer instance. - Private* const d; + KEditScheduleDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KEditScheduleDlg) }; #endif diff --git a/kmymoney/dialogs/keditscheduledlg.ui b/kmymoney/dialogs/keditscheduledlg.ui new file mode 100644 index 000000000..0b686493f --- /dev/null +++ b/kmymoney/dialogs/keditscheduledlg.ui @@ -0,0 +1,469 @@ + + + KEditScheduleDlg + + + + 0 + 0 + 798 + 640 + + + + Edit Scheduled transaction + + + true + + + + + + + + + + Schedule name: + + + false + + + + + + + Qt::StrongFocus + + + + + + + + + + + Frequency: + + + false + + + + + + + Qt::StrongFocus + + + Number of selected periods between entries + + + 1 + + + 999 + + + + + + + + + + + + + + Payment information + + + + + + + + Payment method + + + false + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 61 + 21 + + + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + 0 + + + 12 + + + + + + + 5 + + + 1 + + + + + + + + + + Options + + + + + + + + + Do nothing + + + + + Change the date to the previous processing day + + + + + Change the date to the next processing day + + + + + + + + If this schedule occurs on a non-processing day: + + + false + + + + + + + + + + + The amount is an estimate because it varies for each payment + + + + + + + false + + + 32767 + + + 10 + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 21 + 20 + + + + + + + + + + Process this schedule always at the last day of a month + + + + + + + Enter this schedule into the register automatically when it is due + + + + + + + This schedule will end at some time + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Number of transactions remaining: + + + false + + + + + + + 0 + + + 9999 + + + + + + + Date of final transaction: + + + false + + + + + + + Qt::StrongFocus + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 16 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+ + KLineEdit + QLineEdit +
klineedit.h
+
+ + KMyMoneyRegister::Register + QWidget +
register.h
+
+ + KMyMoneyGeneralCombo + QWidget +
kmymoneymvccombo.h
+ 1 +
+ + KMyMoneyOccurrencePeriodCombo + QWidget +
kmymoneymvccombo.h
+ 1 +
+ + KMyMoneyTransactionForm::TransactionForm + QWidget +
transactionform.h
+
+ + kMyMoneyDateInput + QWidget +
kmymoneydateinput.h
+
+
+ + + + m_endSeriesEdit + toggled(bool) + m_endOptionsFrame + setEnabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + + m_estimateEdit + toggled(bool) + m_variation + setEnabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + + buttonBox + accepted() + KEditScheduleDlg + accept() + + + 398 + 616 + + + 398 + 319 + + + + + buttonBox + rejected() + KEditScheduleDlg + reject() + + + 398 + 616 + + + 398 + 319 + + + + +
diff --git a/kmymoney/dialogs/keditscheduledlgdecl.ui b/kmymoney/dialogs/keditscheduledlgdecl.ui deleted file mode 100644 index 2caa9321b..000000000 --- a/kmymoney/dialogs/keditscheduledlgdecl.ui +++ /dev/null @@ -1,496 +0,0 @@ - - - - - - KEditScheduleDlgDecl - - - - 0 - 0 - 798 - 640 - - - - Edit Scheduled transaction - - - true - - - - - - - - - - Schedule name: - - - false - - - - - - - Qt::StrongFocus - - - - - - - - - - - Frequency: - - - false - - - - - - - 999 - - - 1 - - - Number of selected periods between entries - - - Qt::StrongFocus - - - - - - - - - - - - - - Payment information - - - - - - - - Payment method - - - false - - - - - - - - 3 - 0 - 0 - 0 - - - - - - - - - 61 - 21 - - - - QSizePolicy::Expanding - - - Qt::Horizontal - - - - - - - - - QFrame::HLine - - - QFrame::Sunken - - - - - - - 0 - - - 12 - - - - Security - - - - - Details - - - - - C - - - - - Payment - - - - - Deposit - - - - - Quantity - - - - - Price - - - - - Value - - - - - Balance - - - - - - - - 5 - - - 1 - - - - - - - - - - Options - - - - - - - - - Do nothing - - - - - Change the date to the previous processing day - - - - - Change the date to the next processing day - - - - - - - - If this schedule occurs on a non-processing day: - - - false - - - - - - - - - - - The amount is an estimate because it varies for each payment - - - - - - - false - - - 10 - - - 32767 - - - - - - - - 21 - 20 - - - - QSizePolicy::Expanding - - - Qt::Horizontal - - - - - - - - - Process this schedule always at the last day of a month - - - - - - - Enter this schedule into the register automatically when it is due - - - - - - - This schedule will end at some time - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - 0 - - - - - - 20 - 20 - - - - QSizePolicy::Fixed - - - Qt::Horizontal - - - - - - - Number of transactions remaining: - - - false - - - - - - - 0 - - - 9999 - - - - - - - Date of final transaction: - - - false - - - - - - - Qt::StrongFocus - - - - - - - - - - - - - - 20 - 16 - - - - QSizePolicy::Expanding - - - Qt::Vertical - - - - - - - 0 - - - 6 - - - - - Help - - - - - - - - 280 - 0 - - - - QSizePolicy::Expanding - - - Qt::Horizontal - - - - - - - OK - - - true - - - true - - - - - - - Cancel - - - - - - - - - - - KComboBox - QComboBox -
kcombobox.h
-
- - KMyMoneyGeneralCombo - QWidget -
kmymoneymvccombo.h
- 1 -
- - KMyMoneyOccurrencePeriodCombo - QWidget -
kmymoneymvccombo.h
- 1 -
- -
- - - buttonOk - clicked() - KEditScheduleDlgDecl - accept() - - - m_endSeriesEdit - toggled(bool) - m_endOptionsFrame - setEnabled(bool) - - - buttonCancel - clicked() - KEditScheduleDlgDecl - reject() - - - m_estimateEdit - toggled(bool) - m_variation - setEnabled(bool) - - -
diff --git a/kmymoney/dialogs/kenterscheduledlg.cpp b/kmymoney/dialogs/kenterscheduledlg.cpp index 0fcdc6656..8fe3f430a 100644 --- a/kmymoney/dialogs/kenterscheduledlg.cpp +++ b/kmymoney/dialogs/kenterscheduledlg.cpp @@ -1,353 +1,379 @@ /*************************************************************************** kenterscheduledlg.cpp ------------------- begin : Sat Apr 7 2007 copyright : (C) 2007 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kenterscheduledlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kenterscheduledlg.h" #include "mymoneyfile.h" #include "mymoneyschedule.h" #include "register.h" #include "transactionform.h" #include "transaction.h" #include "transactioneditor.h" #include "kmymoneyutils.h" #include "kmymoneylineedit.h" #include "kmymoneydateinput.h" #include "kmymoney.h" #include "icons/icons.h" #include "mymoneyenums.h" +#include "dialogenums.h" using namespace Icons; -class KEnterScheduleDlg::Private +class KEnterScheduleDlgPrivate { + Q_DISABLE_COPY(KEnterScheduleDlgPrivate) + public: - Private() : m_item(0), m_showWarningOnce(true) {} - ~Private() {} + KEnterScheduleDlgPrivate() : + ui(new Ui::KEnterScheduleDlg), + m_item(nullptr), + m_showWarningOnce(true) + { + } + ~KEnterScheduleDlgPrivate() + { + delete ui; + } + + Ui::KEnterScheduleDlg *ui; MyMoneySchedule m_schedule; KMyMoneyRegister::Transaction* m_item; QWidgetList m_tabOrderWidgets; bool m_showWarningOnce; - KMyMoneyUtils::EnterScheduleResultCodeE m_extendedReturnCode; + eDialogs::ScheduleResultCode m_extendedReturnCode; }; KEnterScheduleDlg::KEnterScheduleDlg(QWidget *parent, const MyMoneySchedule& schedule) : - KEnterScheduleDlgDecl(parent), - d(new Private) + QDialog(parent), + d_ptr(new KEnterScheduleDlgPrivate) { + Q_D(KEnterScheduleDlg); + d->ui->setupUi(this); d->m_schedule = schedule; - d->m_extendedReturnCode = KMyMoneyUtils::Enter; - buttonOk->setIcon(QIcon::fromTheme(g_Icons[Icon::KeyEnter])); - buttonSkip->setIcon(QIcon::fromTheme(g_Icons[Icon::MediaSeekForward])); - KGuiItem::assign(buttonCancel, KStandardGuiItem::cancel()); - KGuiItem::assign(buttonHelp, KStandardGuiItem::help()); - buttonIgnore->setHidden(true); - buttonSkip->setHidden(true); + d->m_extendedReturnCode = eDialogs::ScheduleResultCode::Enter; + d->ui->buttonOk->setIcon(QIcon::fromTheme(g_Icons[Icon::KeyEnter])); + d->ui->buttonSkip->setIcon(QIcon::fromTheme(g_Icons[Icon::MediaSeekForward])); + KGuiItem::assign(d->ui->buttonCancel, KStandardGuiItem::cancel()); + KGuiItem::assign(d->ui->buttonHelp, KStandardGuiItem::help()); + d->ui->buttonIgnore->setHidden(true); + d->ui->buttonSkip->setHidden(true); // make sure, we have a tabbar with the form - KMyMoneyTransactionForm::TabBar* tabbar = m_form->tabBar(m_form->parentWidget()); + KMyMoneyTransactionForm::TabBar* tabbar = d->ui->m_form->tabBar(d->ui->m_form->parentWidget()); // we never need to see the register - m_register->hide(); + d->ui->m_register->hide(); // ... setup the form ... - m_form->setupForm(d->m_schedule.account()); + d->ui->m_form->setupForm(d->m_schedule.account()); // ... and the register ... - m_register->clear(); + d->ui->m_register->clear(); // ... now add the transaction to register and form ... MyMoneyTransaction t = transaction(); - d->m_item = KMyMoneyRegister::Register::transactionFactory(m_register, t, + d->m_item = KMyMoneyRegister::Register::transactionFactory(d->ui->m_register, t, d->m_schedule.transaction().splits().isEmpty() ? MyMoneySplit() : d->m_schedule.transaction().splits().front(), 0); - m_register->selectItem(d->m_item); + d->ui->m_register->selectItem(d->m_item); // show the account row d->m_item->setShowRowInForm(0, true); - m_form->slotSetTransaction(d->m_item); + d->ui->m_form->slotSetTransaction(d->m_item); // no need to see the tabbar tabbar->hide(); // setup name and type - m_scheduleName->setText(d->m_schedule.name()); - m_type->setText(KMyMoneyUtils::scheduleTypeToString(d->m_schedule.type())); + d->ui->m_scheduleName->setText(d->m_schedule.name()); + d->ui->m_type->setText(KMyMoneyUtils::scheduleTypeToString(d->m_schedule.type())); - connect(buttonHelp, SIGNAL(clicked()), this, SLOT(slotShowHelp())); - connect(buttonIgnore, SIGNAL(clicked()), this, SLOT(slotIgnore())); - connect(buttonSkip, SIGNAL(clicked()), this, SLOT(slotSkip())); + connect(d->ui->buttonHelp, &QAbstractButton::clicked, this, &KEnterScheduleDlg::slotShowHelp); + connect(d->ui->buttonIgnore, &QAbstractButton::clicked, this, &KEnterScheduleDlg::slotIgnore); + connect(d->ui->buttonSkip, &QAbstractButton::clicked, this, &KEnterScheduleDlg::slotSkip); } KEnterScheduleDlg::~KEnterScheduleDlg() { + Q_D(KEnterScheduleDlg); delete d; } -KMyMoneyUtils::EnterScheduleResultCodeE KEnterScheduleDlg::resultCode() const +eDialogs::ScheduleResultCode KEnterScheduleDlg::resultCode() const { + Q_D(const KEnterScheduleDlg); if (result() == QDialog::Accepted) return d->m_extendedReturnCode; - return KMyMoneyUtils::Cancel; + return eDialogs::ScheduleResultCode::Cancel; } void KEnterScheduleDlg::showExtendedKeys(bool visible) { - buttonIgnore->setVisible(visible); - buttonSkip->setVisible(visible); + Q_D(KEnterScheduleDlg); + d->ui->buttonIgnore->setVisible(visible); + d->ui->buttonSkip->setVisible(visible); } void KEnterScheduleDlg::slotIgnore() { - d->m_extendedReturnCode = KMyMoneyUtils::Ignore; + Q_D(KEnterScheduleDlg); + d->m_extendedReturnCode = eDialogs::ScheduleResultCode::Ignore; accept(); } void KEnterScheduleDlg::slotSkip() { - d->m_extendedReturnCode = KMyMoneyUtils::Skip; + Q_D(KEnterScheduleDlg); + d->m_extendedReturnCode = eDialogs::ScheduleResultCode::Skip; accept(); } MyMoneyTransaction KEnterScheduleDlg::transaction() { - MyMoneyTransaction t = d->m_schedule.transaction(); + Q_D(KEnterScheduleDlg); + auto t = d->m_schedule.transaction(); try { if (d->m_schedule.type() == eMyMoney::Schedule::Type::LoanPayment) { KMyMoneyUtils::calculateAutoLoan(d->m_schedule, t, QMap()); } } catch (const MyMoneyException &e) { KMessageBox::detailedError(this, i18n("Unable to load schedule details"), e.what()); } t.clearId(); t.setEntryDate(QDate()); return t; } QDate KEnterScheduleDlg::date(const QDate& _date) const { - QDate date(_date); + Q_D(const KEnterScheduleDlg); + auto date(_date); return d->m_schedule.adjustedDate(date, d->m_schedule.weekendOption()); } void KEnterScheduleDlg::resizeEvent(QResizeEvent* ev) { - m_register->resize(KMyMoneyRegister::DetailColumn); - m_form->resize(KMyMoneyTransactionForm::ValueColumn1); - KEnterScheduleDlgDecl::resizeEvent(ev); + Q_UNUSED(ev) + Q_D(KEnterScheduleDlg); + d->ui->m_register->resize(KMyMoneyRegister::DetailColumn); + d->ui->m_form->resize(KMyMoneyTransactionForm::ValueColumn1); + QDialog::resizeEvent(ev); } - void KEnterScheduleDlg::slotSetupSize() { resize(width(), minimumSizeHint().height()); } int KEnterScheduleDlg::exec() { + Q_D(KEnterScheduleDlg); if (d->m_showWarningOnce) { d->m_showWarningOnce = false; KMessageBox::information(this, QString("") + i18n("

Please check that all the details in the following dialog are correct and press OK.

Editable data can be changed and can either be applied to just this occurrence or for all subsequent occurrences for this schedule. (You will be asked what you intend after pressing OK in the following dialog)

") + QString("
"), i18n("Enter scheduled transaction"), "EnterScheduleDlgInfo"); } // force the initial height to be as small as possible QTimer::singleShot(0, this, SLOT(slotSetupSize())); - - return KEnterScheduleDlgDecl::exec(); + return QDialog::exec(); } TransactionEditor* KEnterScheduleDlg::startEdit() { - KMyMoneyRegister::SelectedTransactions list(m_register); - TransactionEditor* editor = d->m_item->createEditor(m_form, list, QDate()); - editor->m_scheduleInfo = d->m_schedule.name(); - editor->m_paymentMethod = d->m_schedule.paymentType(); + Q_D(KEnterScheduleDlg); + KMyMoneyRegister::SelectedTransactions list(d->ui->m_register); + TransactionEditor* editor = d->m_item->createEditor(d->ui->m_form, list, QDate()); + editor->setScheduleInfo(d->m_schedule.name()); + editor->setPaymentMethod(d->m_schedule.paymentType()); // check that we use the same transaction commodity in all selected transactions // if not, we need to update this in the editor's list. The user can also bail out // of this operation which means that we have to stop editing here. if (editor) { if (!editor->fixTransactionCommodity(d->m_schedule.account())) { // if the user wants to quit, we need to destroy the editor // and bail out delete editor; editor = 0; } } if (editor) { - connect(editor, SIGNAL(transactionDataSufficient(bool)), buttonOk, SLOT(setEnabled(bool))); - connect(editor, SIGNAL(escapePressed()), buttonCancel, SLOT(animateClick())); - connect(editor, SIGNAL(returnPressed()), buttonOk, SLOT(animateClick())); + connect(editor, &TransactionEditor::transactionDataSufficient, d->ui->buttonOk, &QWidget::setEnabled); + connect(editor, &TransactionEditor::escapePressed, d->ui->buttonCancel, &QAbstractButton::animateClick); + connect(editor, &TransactionEditor::returnPressed, d->ui->buttonOk, &QAbstractButton::animateClick); - connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), editor, SLOT(slotReloadEditWidgets())); + connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, editor, &TransactionEditor::slotReloadEditWidgets); // connect(editor, SIGNAL(finishEdit(KMyMoneyRegister::SelectedTransactions)), this, SLOT(slotLeaveEditMode(KMyMoneyRegister::SelectedTransactions))); - connect(editor, SIGNAL(createPayee(QString,QString&)), kmymoney, SLOT(slotPayeeNew(QString,QString&))); - connect(editor, SIGNAL(createTag(QString,QString&)), kmymoney, SLOT(slotTagNew(QString,QString&))); - connect(editor, SIGNAL(createCategory(MyMoneyAccount&,MyMoneyAccount)), kmymoney, SLOT(slotCategoryNew(MyMoneyAccount&,MyMoneyAccount))); - connect(editor, SIGNAL(createSecurity(MyMoneyAccount&,MyMoneyAccount)), kmymoney, SLOT(slotInvestmentNew(MyMoneyAccount&,MyMoneyAccount))); - connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), editor, SLOT(slotReloadEditWidgets())); + connect(editor, &TransactionEditor::createPayee, kmymoney, static_cast(&KMyMoneyApp::slotPayeeNew)); + connect(editor, &TransactionEditor::createTag, kmymoney, static_cast(&KMyMoneyApp::slotTagNew)); + connect(editor, &TransactionEditor::createCategory, kmymoney, static_cast(&KMyMoneyApp::slotCategoryNew)); + connect(editor, &TransactionEditor::createSecurity, kmymoney, static_cast(&KMyMoneyApp::slotInvestmentNew)); + connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, editor, &TransactionEditor::slotReloadEditWidgets); // create the widgets, place them in the parent and load them with data // setup tab order d->m_tabOrderWidgets.clear(); KMyMoneyRegister::Action action = KMyMoneyRegister::ActionWithdrawal; switch (d->m_schedule.type()) { case eMyMoney::Schedule::Type::Transfer: action = KMyMoneyRegister::ActionTransfer; break; case eMyMoney::Schedule::Type::Deposit: action = KMyMoneyRegister::ActionDeposit; break; case eMyMoney::Schedule::Type::LoanPayment: switch (d->m_schedule.paymentType()) { case eMyMoney::Schedule::PaymentType::DirectDeposit: case eMyMoney::Schedule::PaymentType::ManualDeposit: action = KMyMoneyRegister::ActionDeposit; break; default: break; } break; default: break; } editor->setup(d->m_tabOrderWidgets, d->m_schedule.account(), action); MyMoneyTransaction t = d->m_schedule.transaction(); QString num = t.splits().first().number(); QWidget* w = editor->haveWidget("number"); if (d->m_schedule.paymentType() == eMyMoney::Schedule::PaymentType::WriteChecque) { - MyMoneyFile* file = MyMoneyFile::instance(); + auto file = MyMoneyFile::instance(); if (file->checkNoUsed(d->m_schedule.account().id(), num)) { // increment and try again num = KMyMoneyUtils::getAdjacentNumber(num); } num = KMyMoneyUtils::nextCheckNumber(d->m_schedule.account()); KMyMoneyUtils::updateLastNumberUsed(d->m_schedule.account(), num); d->m_schedule.account().setValue("lastNumberUsed", num); if (w) { dynamic_cast(w)->loadText(num); } } else { // if it's not a check, then we need to clear // a possibly assigned check number if (w) dynamic_cast(w)->loadText(QString()); } Q_ASSERT(!d->m_tabOrderWidgets.isEmpty()); // editor->setup() leaves the tabbar as the last widget in the stack, but we // need it as first here. So we move it around. w = editor->haveWidget("tabbar"); if (w) { int idx = d->m_tabOrderWidgets.indexOf(w); if (idx != -1) { d->m_tabOrderWidgets.removeAt(idx); d->m_tabOrderWidgets.push_front(w); } } // don't forget our three buttons - d->m_tabOrderWidgets.append(buttonOk); - d->m_tabOrderWidgets.append(buttonCancel); - d->m_tabOrderWidgets.append(buttonHelp); + d->m_tabOrderWidgets.append(d->ui->buttonOk); + d->m_tabOrderWidgets.append(d->ui->buttonCancel); + d->m_tabOrderWidgets.append(d->ui->buttonHelp); - for (int i = 0; i < d->m_tabOrderWidgets.size(); ++i) { + for (auto i = 0; i < d->m_tabOrderWidgets.size(); ++i) { QWidget* w = d->m_tabOrderWidgets.at(i); if (w) { w->installEventFilter(this); w->installEventFilter(editor); } } // Check if the editor has some preference on where to set the focus // If not, set the focus to the first widget in the tab order QWidget* focusWidget = editor->firstWidget(); if (!focusWidget) focusWidget = d->m_tabOrderWidgets.first(); focusWidget->setFocus(); // Make sure, we use the adjusted date kMyMoneyDateInput* dateEdit = dynamic_cast(editor->haveWidget("postdate")); if (dateEdit) { dateEdit->setDate(d->m_schedule.adjustedNextDueDate()); } } return editor; } bool KEnterScheduleDlg::focusNextPrevChild(bool next) { - bool rc = false; - QWidget *w = 0; - - w = qApp->focusWidget(); + Q_D(KEnterScheduleDlg); + auto rc = false; + + auto w = qApp->focusWidget(); int currentWidgetIndex = d->m_tabOrderWidgets.indexOf(w); while (w && currentWidgetIndex == -1) { // qDebug("'%s' not in list, use parent", w->className()); w = w->parentWidget(); currentWidgetIndex = d->m_tabOrderWidgets.indexOf(w); } if (currentWidgetIndex != -1) { // if(w) qDebug("tab order is at '%s'", w->className()); currentWidgetIndex += next ? 1 : -1; if (currentWidgetIndex < 0) currentWidgetIndex = d->m_tabOrderWidgets.size() - 1; else if (currentWidgetIndex >= d->m_tabOrderWidgets.size()) currentWidgetIndex = 0; w = d->m_tabOrderWidgets[currentWidgetIndex]; // qDebug("currentWidgetIndex = %d, w = %p", currentWidgetIndex, w); if (((w->focusPolicy() & Qt::TabFocus) == Qt::TabFocus) && w->isVisible() && w->isEnabled()) { // qDebug("Selecting '%s' as focus", w->className()); w->setFocus(); rc = true; } } return rc; } void KEnterScheduleDlg::slotShowHelp() { KHelpClient::invokeHelp("details.schedules.entering"); } diff --git a/kmymoney/dialogs/kenterscheduledlg.h b/kmymoney/dialogs/kenterscheduledlg.h index eeb1faa07..05994e5d7 100644 --- a/kmymoney/dialogs/kenterscheduledlg.h +++ b/kmymoney/dialogs/kenterscheduledlg.h @@ -1,100 +1,98 @@ /*************************************************************************** kenterscheduledlg.h - description ------------------- begin : Sat Apr 7 2007 copyright : (C) 2007 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KENTERSCHEDULEDLG_H #define KENTERSCHEDULEDLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes class MyMoneySchedule; +class MyMoneyTransaction; class TransactionEditor; -#include "ui_kenterscheduledlgdecl.h" -#include "kmymoneyutils.h" +namespace Ui { class KEnterScheduleDlg; } + +namespace eDialogs { enum class ScheduleResultCode; } /** * @author Thomas Baumgart */ -class KEnterScheduleDlgDecl : public QDialog, public Ui::KEnterScheduleDlgDecl -{ -public: - KEnterScheduleDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; -class KEnterScheduleDlg : public KEnterScheduleDlgDecl + +class KEnterScheduleDlgPrivate; +class KEnterScheduleDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KEnterScheduleDlg) + public: - KEnterScheduleDlg(QWidget *parent, const MyMoneySchedule& schedule); + explicit KEnterScheduleDlg(QWidget *parent, const MyMoneySchedule& schedule); ~KEnterScheduleDlg(); TransactionEditor* startEdit(); MyMoneyTransaction transaction(); /** * Show (or hide) the extended dialog keys for 'Skip' and 'Ignore' * depending on the value of the parameter @a visible which defaults * to @a true. */ void showExtendedKeys(bool visible = true); /** * Return the extended result code. Usage of the returned * value only makes sense, once the dialog has been executed. * Before execution it returns @a Cancel. */ - KMyMoneyUtils::EnterScheduleResultCodeE resultCode() const; + eDialogs::ScheduleResultCode resultCode() const; protected: /// Overridden for internal reasons. No API changes. - bool focusNextPrevChild(bool next); + bool focusNextPrevChild(bool next) override; /** * This method returns the adjusts @a _date according to * the setting of the schedule's weekend option. */ QDate date(const QDate& _date) const; - void resizeEvent(QResizeEvent* ev); + void resizeEvent(QResizeEvent* ev) override; public slots: - int exec(); + int exec() override; private slots: void slotSetupSize(); void slotShowHelp(); void slotIgnore(); void slotSkip(); private: - /// \internal d-pointer class. - class Private; - /// \internal d-pointer instance. - Private* const d; + KEnterScheduleDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KEnterScheduleDlg) }; #endif diff --git a/kmymoney/dialogs/kenterscheduledlgdecl.ui b/kmymoney/dialogs/kenterscheduledlg.ui similarity index 98% rename from kmymoney/dialogs/kenterscheduledlgdecl.ui rename to kmymoney/dialogs/kenterscheduledlg.ui index 34ac80b68..294059110 100644 --- a/kmymoney/dialogs/kenterscheduledlgdecl.ui +++ b/kmymoney/dialogs/kenterscheduledlg.ui @@ -1,318 +1,318 @@ - KEnterScheduleDlgDecl - + KEnterScheduleDlg + 0 0 679 410 Enter Schedule true Schedule Details 5 5 1 1 70 0 Name: false false 20 0 QSizePolicy::Expanding Qt::Horizontal 5 5 1 1 70 0 Type: false 5 5 1 1 false 0 12 Security Details C Payment Deposit Quantity Price Value Balance 1 5 5 1 5 5 1 QFrame::HLine QFrame::Sunken Help 190 20 QSizePolicy::Expanding Qt::Horizontal Enter true true Enter the transaction and advance the next due date of this schedule to the next payment date. &Skip true Do not enter the transaction but advance the next due date of this schedule to the next payment date. Ignore Do not enter or skip payments for this schedule but continue with the next schedule. Cancel Cancel processing of schedule entry. buttonOk clicked() - KEnterScheduleDlgDecl + KEnterScheduleDlg accept() buttonCancel clicked() - KEnterScheduleDlgDecl + KEnterScheduleDlg reject() diff --git a/kmymoney/dialogs/kequitypriceupdateconfdlg.cpp b/kmymoney/dialogs/kequitypriceupdateconfdlg.cpp index af47ead35..3f8e4994b 100644 --- a/kmymoney/dialogs/kequitypriceupdateconfdlg.cpp +++ b/kmymoney/dialogs/kequitypriceupdateconfdlg.cpp @@ -1,128 +1,155 @@ /******************************************************************************* * kequitypriceupdateconfdlg.cpp * ------------------ * begin : Sun May 21 2017 * copyright : (C) 2017 by Łukasz Wojnilowicz * email : lukasz.wojnilowicz@gmail.com ********************************************************************************/ /******************************************************************************* * * * 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. * * * ********************************************************************************/ #include "kequitypriceupdateconfdlg.h" #include "ui_kequitypriceupdateconfdlg.h" -EquityPriceUpdateConfDlg::EquityPriceUpdateConfDlg(const updatingPricePolicyE policy) : ui(new Ui::EquityPriceUpdateConfDlg) +#include "dialogenums.h" + +class EquityPriceUpdateConfDlgPrivate +{ + Q_DISABLE_COPY(EquityPriceUpdateConfDlgPrivate) + +public: + EquityPriceUpdateConfDlgPrivate() : + ui(new Ui::EquityPriceUpdateConfDlg) + { + } + + ~EquityPriceUpdateConfDlgPrivate() + { + delete ui; + } + + void updatingPricePolicyChanged(const eDialogs::UpdatePrice policy, bool toggled) + { + if (!toggled) + return; + + switch(policy) { + case eDialogs::UpdatePrice::All: + ui->m_updateMissing->setChecked(false); + ui->m_updateDownloaded->setChecked(false); + ui->m_updateSource->setChecked(false); + ui->m_ask->setChecked(false); + break; + case eDialogs::UpdatePrice::Missing: + ui->m_updateAll->setChecked(false); + ui->m_updateDownloaded->setChecked(false); + ui->m_updateSource->setChecked(false); + ui->m_ask->setChecked(false); + break; + case eDialogs::UpdatePrice::Downloaded: + ui->m_updateAll->setChecked(false); + ui->m_updateMissing->setChecked(false); + ui->m_updateSource->setChecked(false); + ui->m_ask->setChecked(false); + break; + case eDialogs::UpdatePrice::SameSource: + ui->m_updateAll->setChecked(false); + ui->m_updateMissing->setChecked(false); + ui->m_updateDownloaded->setChecked(false); + ui->m_ask->setChecked(false); + break; + case eDialogs::UpdatePrice::Ask: + ui->m_updateAll->setChecked(false); + ui->m_updateDownloaded->setChecked(false); + ui->m_updateSource->setChecked(false); + ui->m_updateMissing->setChecked(false); + break; + } + m_updatingPricePolicy = policy; + } + + Ui::EquityPriceUpdateConfDlg *ui; + eDialogs::UpdatePrice m_updatingPricePolicy; +}; + +EquityPriceUpdateConfDlg::EquityPriceUpdateConfDlg(eDialogs::UpdatePrice policy) : + QDialog(nullptr), + d_ptr(new EquityPriceUpdateConfDlgPrivate) { - ui->setupUi(this); + Q_D(EquityPriceUpdateConfDlg); + d->ui->setupUi(this); switch(policy) { - case eUpdateAllPrices: - ui->m_updateAll->setChecked(true); - break; - case eUpdateMissingPrices: - ui->m_updateMissing->setChecked(true); + case eDialogs::UpdatePrice::All: + d->ui->m_updateAll->setChecked(true); break; - case eUpdateDownloadedPrices: - ui->m_updateDownloaded->setChecked(true); + case eDialogs::UpdatePrice::Missing: + d->ui->m_updateMissing->setChecked(true); break; - case eUpdateSameSourcePrices: - ui->m_updateSource->setChecked(true); + case eDialogs::UpdatePrice::Downloaded: + d->ui->m_updateDownloaded->setChecked(true); break; - case eAsk: - ui->m_ask->setChecked(true); + case eDialogs::UpdatePrice::SameSource: + d->ui->m_updateSource->setChecked(true); break; - default: + case eDialogs::UpdatePrice::Ask: + d->ui->m_ask->setChecked(true); break; } - m_updatingPricePolicy = policy; - connect(ui->m_updateAll, &QAbstractButton::toggled, this, &EquityPriceUpdateConfDlg::updateAllToggled); - connect(ui->m_updateMissing, &QAbstractButton::toggled, this, &EquityPriceUpdateConfDlg::updateMissingToggled); - connect(ui->m_updateDownloaded, &QAbstractButton::toggled, this, &EquityPriceUpdateConfDlg::updateDownloadedToggled); - connect(ui->m_updateSource, &QAbstractButton::toggled, this, &EquityPriceUpdateConfDlg::updateSameSourceToggled); - connect(ui->m_ask, &QAbstractButton::toggled, this, &EquityPriceUpdateConfDlg::askToggled); + d->m_updatingPricePolicy = policy; + connect(d->ui->m_updateAll, &QAbstractButton::toggled, this, &EquityPriceUpdateConfDlg::updateAllToggled); + connect(d->ui->m_updateMissing, &QAbstractButton::toggled, this, &EquityPriceUpdateConfDlg::updateMissingToggled); + connect(d->ui->m_updateDownloaded, &QAbstractButton::toggled, this, &EquityPriceUpdateConfDlg::updateDownloadedToggled); + connect(d->ui->m_updateSource, &QAbstractButton::toggled, this, &EquityPriceUpdateConfDlg::updateSameSourceToggled); + connect(d->ui->m_ask, &QAbstractButton::toggled, this, &EquityPriceUpdateConfDlg::askToggled); } EquityPriceUpdateConfDlg::~EquityPriceUpdateConfDlg() { - delete ui; + Q_D(EquityPriceUpdateConfDlg); + delete d; } void EquityPriceUpdateConfDlg::updateAllToggled(bool toggled) { - updatingPricePolicyChanged(eUpdateAllPrices, toggled); + Q_D(EquityPriceUpdateConfDlg); + d->updatingPricePolicyChanged(eDialogs::UpdatePrice::All, toggled); } void EquityPriceUpdateConfDlg::updateMissingToggled(bool toggled) { - updatingPricePolicyChanged(eUpdateMissingPrices, toggled); + Q_D(EquityPriceUpdateConfDlg); + d->updatingPricePolicyChanged(eDialogs::UpdatePrice::Missing, toggled); } void EquityPriceUpdateConfDlg::updateDownloadedToggled(bool toggled) { - updatingPricePolicyChanged(eUpdateDownloadedPrices, toggled); + Q_D(EquityPriceUpdateConfDlg); + d->updatingPricePolicyChanged(eDialogs::UpdatePrice::Downloaded, toggled); } void EquityPriceUpdateConfDlg::updateSameSourceToggled(bool toggled) { - updatingPricePolicyChanged(eUpdateSameSourcePrices, toggled); + Q_D(EquityPriceUpdateConfDlg); + d->updatingPricePolicyChanged(eDialogs::UpdatePrice::SameSource, toggled); } void EquityPriceUpdateConfDlg::askToggled(bool toggled) { - updatingPricePolicyChanged(eAsk, toggled); + Q_D(EquityPriceUpdateConfDlg); + d->updatingPricePolicyChanged(eDialogs::UpdatePrice::Ask, toggled); } -updatingPricePolicyE EquityPriceUpdateConfDlg::policy() +eDialogs::UpdatePrice EquityPriceUpdateConfDlg::policy() const { - return m_updatingPricePolicy; -} - -void EquityPriceUpdateConfDlg::updatingPricePolicyChanged(const updatingPricePolicyE policy, bool toggled) -{ - if (!toggled) - return; - - switch(policy) { - case eUpdateAllPrices: - ui->m_updateMissing->setChecked(false); - ui->m_updateDownloaded->setChecked(false); - ui->m_updateSource->setChecked(false); - ui->m_ask->setChecked(false); - break; - case eUpdateMissingPrices: - ui->m_updateAll->setChecked(false); - ui->m_updateDownloaded->setChecked(false); - ui->m_updateSource->setChecked(false); - ui->m_ask->setChecked(false); - break; - case eUpdateDownloadedPrices: - ui->m_updateAll->setChecked(false); - ui->m_updateMissing->setChecked(false); - ui->m_updateSource->setChecked(false); - ui->m_ask->setChecked(false); - break; - case eUpdateSameSourcePrices: - ui->m_updateAll->setChecked(false); - ui->m_updateMissing->setChecked(false); - ui->m_updateDownloaded->setChecked(false); - ui->m_ask->setChecked(false); - break; - case eAsk: - ui->m_updateAll->setChecked(false); - ui->m_updateDownloaded->setChecked(false); - ui->m_updateSource->setChecked(false); - ui->m_updateMissing->setChecked(false); - break; - default: - break; - } - m_updatingPricePolicy = policy; + Q_D(const EquityPriceUpdateConfDlg); + return d->m_updatingPricePolicy; } diff --git a/kmymoney/dialogs/kequitypriceupdateconfdlg.h b/kmymoney/dialogs/kequitypriceupdateconfdlg.h index e4403e386..6a8a0b55d 100644 --- a/kmymoney/dialogs/kequitypriceupdateconfdlg.h +++ b/kmymoney/dialogs/kequitypriceupdateconfdlg.h @@ -1,53 +1,49 @@ /******************************************************************************* * kequitypriceupdateconfdlg.cpp * ------------------ * begin : Sun May 21 2017 * copyright : (C) 2017 by Łukasz Wojnilowicz * email : lukasz.wojnilowicz@gmail.com ********************************************************************************/ /******************************************************************************* * * * 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. * * * ********************************************************************************/ #ifndef KEQUITYPRICEUPDATECONFDLG_H #define KEQUITYPRICEUPDATECONFDLG_H #include -enum updatingPricePolicyE : int {eUpdateAllPrices = 0, eUpdateMissingPrices, eUpdateDownloadedPrices, eUpdateSameSourcePrices, eAsk, eUpdatingPricePolicyEnd}; - -namespace Ui -{ -class EquityPriceUpdateConfDlg; -} +namespace eDialogs { enum class UpdatePrice; } +class EquityPriceUpdateConfDlgPrivate; class EquityPriceUpdateConfDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(EquityPriceUpdateConfDlg) public: - explicit EquityPriceUpdateConfDlg(const updatingPricePolicyE policy); + explicit EquityPriceUpdateConfDlg(eDialogs::UpdatePrice policy); ~EquityPriceUpdateConfDlg(); - Ui::EquityPriceUpdateConfDlg* ui; - - updatingPricePolicyE policy(); -private: - void updatingPricePolicyChanged(const updatingPricePolicyE policy, bool toggled); + eDialogs::UpdatePrice policy() const; - updatingPricePolicyE m_updatingPricePolicy; private slots: void updateAllToggled(bool toggled); void updateMissingToggled(bool toggled); void updateDownloadedToggled(bool toggled); void updateSameSourceToggled(bool toggled); void askToggled(bool toggled); + +private: + EquityPriceUpdateConfDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(EquityPriceUpdateConfDlg) }; #endif // KEQUITYPRICEUPDATECONFDLG_H diff --git a/kmymoney/dialogs/kequitypriceupdatedlg.cpp b/kmymoney/dialogs/kequitypriceupdatedlg.cpp index 0fe8baa41..d5d6f6a80 100644 --- a/kmymoney/dialogs/kequitypriceupdatedlg.cpp +++ b/kmymoney/dialogs/kequitypriceupdatedlg.cpp @@ -1,749 +1,805 @@ /*************************************************************************** kequitypriceupdatedlg.cpp - description ------------------- begin : Mon Sep 1 2003 copyright : (C) 2000-2003 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio Ace Jones - 2017 Łukasz Wojniłowicz + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kequitypriceupdatedlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include +#include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kequitypriceupdatedlg.h" + #include "kmymoney.h" #include "mymoneyfile.h" #include "mymoneyaccount.h" #include "mymoneysecurity.h" #include "mymoneyprice.h" +#include "webpricequote.h" +#include "kequitypriceupdateconfdlg.h" +#include "dialogenums.h" #define WEBID_COL 0 #define NAME_COL 1 #define PRICE_COL 2 #define DATE_COL 3 #define KMMID_COL 4 #define SOURCE_COL 5 -KEquityPriceUpdateDlg::KEquityPriceUpdateDlg(QWidget *parent, const QString& securityId) : - KEquityPriceUpdateDlgDecl(parent), - m_fUpdateAll(false) +class KEquityPriceUpdateDlgPrivate { - QStringList headerList; - headerList << i18n("ID") << i18nc("Equity name", "Name") - << i18n("Price") << i18n("Date"); + Q_DISABLE_COPY(KEquityPriceUpdateDlgPrivate) + Q_DECLARE_PUBLIC(KEquityPriceUpdateDlg) + +public: + KEquityPriceUpdateDlgPrivate(KEquityPriceUpdateDlg *qq) : + q_ptr(qq), + ui(new Ui::KEquityPriceUpdateDlg) + { + } - lvEquityList->header()->setSortIndicator(0, Qt::AscendingOrder); - lvEquityList->setColumnWidth(NAME_COL, 125); + ~KEquityPriceUpdateDlgPrivate() + { + delete ui; + } - // This is a "get it up and running" hack. Will replace this in the future. - headerList << i18nc("Internal identifier", "Internal ID") - << i18nc("Online quote source", "Source"); - lvEquityList->setColumnWidth(KMMID_COL, 0); + void init(const QString& securityId) + { + Q_Q(KEquityPriceUpdateDlg); + ui->setupUi(q); + m_fUpdateAll = false; + QStringList headerList; + headerList << i18n("ID") << i18nc("Equity name", "Name") + << i18n("Price") << i18n("Date"); - lvEquityList->setHeaderLabels(headerList); + ui->lvEquityList->header()->setSortIndicator(0, Qt::AscendingOrder); + ui->lvEquityList->setColumnWidth(NAME_COL, 125); - lvEquityList->setSelectionMode(QAbstractItemView::MultiSelection); - lvEquityList->setAllColumnsShowFocus(true); + // This is a "get it up and running" hack. Will replace this in the future. + headerList << i18nc("Internal identifier", "Internal ID") + << i18nc("Online quote source", "Source"); + ui->lvEquityList->setColumnWidth(KMMID_COL, 0); - btnUpdateAll->setEnabled(false); + ui->lvEquityList->setHeaderLabels(headerList); - MyMoneyFile* file = MyMoneyFile::instance(); + ui->lvEquityList->setSelectionMode(QAbstractItemView::MultiSelection); + ui->lvEquityList->setAllColumnsShowFocus(true); - // - // Add each price pair that we know about - // + ui->btnUpdateAll->setEnabled(false); - // send in securityId == "XXX YYY" to get a single-shot update for XXX to YYY. - // for consistency reasons, this accepts the same delimiters as WebPriceQuote::launch() - QRegExp splitrx("([0-9a-z\\.]+)[^a-z0-9]+([0-9a-z\\.]+)", Qt::CaseInsensitive); - MyMoneySecurityPair currencyIds; - if (splitrx.indexIn(securityId) != -1) { - currencyIds = MyMoneySecurityPair(splitrx.cap(1), splitrx.cap(2)); - } + auto file = MyMoneyFile::instance(); - MyMoneyPriceList prices = file->priceList(); - for (MyMoneyPriceList::ConstIterator it_price = prices.constBegin(); it_price != prices.constEnd(); ++it_price) { - const MyMoneySecurityPair& pair = it_price.key(); - if (file->security(pair.first).isCurrency() && (securityId.isEmpty() || (pair == currencyIds))) { - const MyMoneyPriceEntries& entries = (*it_price); - if (entries.count() > 0 && entries.begin().key() <= QDate::currentDate()) { - addPricePair(pair); - btnUpdateAll->setEnabled(true); - } - } - } + // + // Add each price pair that we know about + // - // - // Add each investment - // - - QList securities = file->securityList(); - for (QList::const_iterator it = securities.constBegin(); it != securities.constEnd(); ++it) { - if (!(*it).isCurrency() - && (securityId.isEmpty() || ((*it).id() == securityId)) - && !(*it).value("kmm-online-source").isEmpty() - ) { - addInvestment(*it); - btnUpdateAll->setEnabled(true); + // send in securityId == "XXX YYY" to get a single-shot update for XXX to YYY. + // for consistency reasons, this accepts the same delimiters as WebPriceQuote::launch() + QRegExp splitrx("([0-9a-z\\.]+)[^a-z0-9]+([0-9a-z\\.]+)", Qt::CaseInsensitive); + MyMoneySecurityPair currencyIds; + if (splitrx.indexIn(securityId) != -1) { + currencyIds = MyMoneySecurityPair(splitrx.cap(1), splitrx.cap(2)); } - } - - // if list is empty, add the request price pair - if (lvEquityList->invisibleRootItem()->childCount() == 0) { - addPricePair(currencyIds, true); - } - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - connect(btnUpdateSelected, SIGNAL(clicked()), this, SLOT(slotUpdateSelectedClicked())); - connect(btnUpdateAll, SIGNAL(clicked()), this, SLOT(slotUpdateAllClicked())); + MyMoneyPriceList prices = file->priceList(); + for (MyMoneyPriceList::ConstIterator it_price = prices.constBegin(); it_price != prices.constEnd(); ++it_price) { + const MyMoneySecurityPair& pair = it_price.key(); + if (file->security(pair.first).isCurrency() && (securityId.isEmpty() || (pair == currencyIds))) { + const MyMoneyPriceEntries& entries = (*it_price); + if (entries.count() > 0 && entries.begin().key() <= QDate::currentDate()) { + addPricePair(pair, false); + ui->btnUpdateAll->setEnabled(true); + } + } + } - connect(m_fromDate, SIGNAL(dateChanged(QDate)), this, SLOT(slotDateChanged())); - connect(m_toDate, SIGNAL(dateChanged(QDate)), this, SLOT(slotDateChanged())); + // + // Add each investment + // + + QList securities = file->securityList(); + for (QList::const_iterator it = securities.constBegin(); it != securities.constEnd(); ++it) { + if (!(*it).isCurrency() + && (securityId.isEmpty() || ((*it).id() == securityId)) + && !(*it).value("kmm-online-source").isEmpty() + ) { + addInvestment(*it); + ui->btnUpdateAll->setEnabled(true); + } + } - connect(&m_webQuote, &WebPriceQuote::csvquote, - this, &KEquityPriceUpdateDlg::slotReceivedCSVQuote); - connect(&m_webQuote, SIGNAL(quote(QString,QString,QDate,double)), - this, SLOT(slotReceivedQuote(QString,QString,QDate,double))); - connect(&m_webQuote, SIGNAL(failed(QString,QString)), - this, SLOT(slotQuoteFailed(QString,QString))); - connect(&m_webQuote, SIGNAL(status(QString)), - this, SLOT(logStatusMessage(QString))); - connect(&m_webQuote, SIGNAL(error(QString)), - this, SLOT(logErrorMessage(QString))); + // if list is empty, add the request price pair + if (ui->lvEquityList->invisibleRootItem()->childCount() == 0) { + addPricePair(currencyIds, true); + } - connect(lvEquityList, SIGNAL(itemSelectionChanged()), this, SLOT(slotUpdateSelection())); + q->connect(ui->btnUpdateSelected, &QAbstractButton::clicked, q, &KEquityPriceUpdateDlg::slotUpdateSelectedClicked); + q->connect(ui->btnUpdateAll, &QAbstractButton::clicked, q, &KEquityPriceUpdateDlg::slotUpdateAllClicked); - connect(btnConfigure, &QAbstractButton::clicked, this, &KEquityPriceUpdateDlg::slotConfigureClicked); + q->connect(ui->m_fromDate, &kMyMoneyDateInput::dateChanged, q, &KEquityPriceUpdateDlg::slotDateChanged); + q->connect(ui->m_toDate, &kMyMoneyDateInput::dateChanged, q, &KEquityPriceUpdateDlg::slotDateChanged); - if (!securityId.isEmpty()) { - btnUpdateSelected->hide(); - btnUpdateAll->hide(); - // delete layout1; + q->connect(&m_webQuote, &WebPriceQuote::csvquote, + q, &KEquityPriceUpdateDlg::slotReceivedCSVQuote); + q->connect(&m_webQuote, &WebPriceQuote::quote, + q, &KEquityPriceUpdateDlg::slotReceivedQuote); + q->connect(&m_webQuote, &WebPriceQuote::failed, + q, &KEquityPriceUpdateDlg::slotQuoteFailed); + q->connect(&m_webQuote, &WebPriceQuote::status, + q, &KEquityPriceUpdateDlg::logStatusMessage); + q->connect(&m_webQuote, &WebPriceQuote::error, + q, &KEquityPriceUpdateDlg::logErrorMessage); - QTimer::singleShot(100, this, SLOT(slotUpdateAllClicked())); - } + q->connect(ui->lvEquityList, &QTreeWidget::itemSelectionChanged, q, &KEquityPriceUpdateDlg::slotUpdateSelection); - // Hide OK button until we have received the first update - buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + q->connect(ui->btnConfigure, &QAbstractButton::clicked, q, &KEquityPriceUpdateDlg::slotConfigureClicked); - slotUpdateSelection(); + if (!securityId.isEmpty()) { + ui->btnUpdateSelected->hide(); + ui->btnUpdateAll->hide(); + // delete layout1; - // previous versions of this dialog allowed to store a "Don't ask again" switch. - // Since we don't support it anymore, we just get rid of it - KSharedConfigPtr config = KSharedConfig::openConfig(); - KConfigGroup grp = config->group("Notification Messages"); - grp.deleteEntry("KEquityPriceUpdateDlg::slotQuoteFailed::Price Update Failed"); - grp.sync(); - grp = config->group("Equity Price Update"); - int policyValue = grp.readEntry("PriceUpdatingPolicy", QString().setNum(eUpdateMissingPrices)).toInt(); - if (policyValue >= eUpdatingPricePolicyEnd || policyValue < eUpdateAllPrices) - m_updatingPricePolicy = eUpdateMissingPrices; - else - m_updatingPricePolicy = static_cast(policyValue); -} + QTimer::singleShot(100, q, SLOT(slotUpdateAllClicked())); + } -KEquityPriceUpdateDlg::~KEquityPriceUpdateDlg() -{ - KSharedConfigPtr config = KSharedConfig::openConfig(); - KConfigGroup grp = config->group("Equity Price Update"); - grp.writeEntry("PriceUpdatingPolicy", static_cast(m_updatingPricePolicy)); - grp.sync(); -} + // Hide OK button until we have received the first update + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + + q->slotUpdateSelection(); + + // previous versions of this dialog allowed to store a "Don't ask again" switch. + // Since we don't support it anymore, we just get rid of it + KSharedConfigPtr config = KSharedConfig::openConfig(); + KConfigGroup grp = config->group("Notification Messages"); + grp.deleteEntry("KEquityPriceUpdateDlg::slotQuoteFailed::Price Update Failed"); + grp.sync(); + grp = config->group("Equity Price Update"); + int policyValue = grp.readEntry("PriceUpdatingPolicy", (int)eDialogs::UpdatePrice::Missing); + if (policyValue > (int)eDialogs::UpdatePrice::Ask || policyValue < (int)eDialogs::UpdatePrice::All) + m_updatingPricePolicy = eDialogs::UpdatePrice::Missing; + else + m_updatingPricePolicy = static_cast(policyValue); + } -void KEquityPriceUpdateDlg::addPricePair(const MyMoneySecurityPair& pair, bool dontCheckExistance) -{ - MyMoneyFile* file = MyMoneyFile::instance(); - - const QString symbol = QString::fromLatin1("%1 > %2").arg(pair.first, pair.second); - const QString id = QString::fromLatin1("%1 %2").arg(pair.first, pair.second); - // Check that the pair does not already exist - if (lvEquityList->findItems(id, Qt::MatchExactly, KMMID_COL).empty()) { - const MyMoneyPrice &pr = file->price(pair.first, pair.second); - if (pr.source() != QLatin1String("KMyMoney")) { - bool keep = true; - if ((pair.first == file->baseCurrency().id()) - || (pair.second == file->baseCurrency().id())) { - const QString& foreignCurrency = file->foreignCurrency(pair.first, pair.second); - // check that the foreign currency is still in use - QList::const_iterator it_a; - QList list; - file->accountList(list); - for (it_a = list.constBegin(); !dontCheckExistance && it_a != list.constEnd(); ++it_a) { - // if it's an account denominated in the foreign currency - // keep it - if (((*it_a).currencyId() == foreignCurrency) - && !(*it_a).isClosed()) - break; - // if it's an investment traded in the foreign currency - // keep it - if ((*it_a).isInvest() && !(*it_a).isClosed()) { - MyMoneySecurity sec = file->security((*it_a).currencyId()); - if (sec.tradingCurrency() == foreignCurrency) + void addPricePair(const MyMoneySecurityPair& pair, bool dontCheckExistance) + { + auto file = MyMoneyFile::instance(); + + const auto symbol = QString::fromLatin1("%1 > %2").arg(pair.first, pair.second); + const auto id = QString::fromLatin1("%1 %2").arg(pair.first, pair.second); + // Check that the pair does not already exist + if (ui->lvEquityList->findItems(id, Qt::MatchExactly, KMMID_COL).empty()) { + const MyMoneyPrice &pr = file->price(pair.first, pair.second); + if (pr.source() != QLatin1String("KMyMoney")) { + bool keep = true; + if ((pair.first == file->baseCurrency().id()) + || (pair.second == file->baseCurrency().id())) { + const QString& foreignCurrency = file->foreignCurrency(pair.first, pair.second); + // check that the foreign currency is still in use + QList::const_iterator it_a; + QList list; + file->accountList(list); + for (it_a = list.constBegin(); !dontCheckExistance && it_a != list.constEnd(); ++it_a) { + // if it's an account denominated in the foreign currency + // keep it + if (((*it_a).currencyId() == foreignCurrency) + && !(*it_a).isClosed()) break; + // if it's an investment traded in the foreign currency + // keep it + if ((*it_a).isInvest() && !(*it_a).isClosed()) { + MyMoneySecurity sec = file->security((*it_a).currencyId()); + if (sec.tradingCurrency() == foreignCurrency) + break; + } + } + // if it is in use, it_a is not equal to list.end() + if (it_a == list.constEnd() && !dontCheckExistance) + keep = false; + } + + if (keep) { + auto item = new QTreeWidgetItem(); + item->setText(WEBID_COL, symbol); + item->setText(NAME_COL, i18n("%1 units in %2", pair.first, pair.second)); + if (pr.isValid()) { + MyMoneySecurity fromCurrency = file->currency(pair.second); + MyMoneySecurity toCurrency = file->currency(pair.first); + item->setText(PRICE_COL, pr.rate(pair.second).formatMoney(fromCurrency.tradingSymbol(), toCurrency.pricePrecision())); + item->setText(DATE_COL, pr.date().toString(Qt::ISODate)); } + item->setText(KMMID_COL, id); + item->setText(SOURCE_COL, "Yahoo Currency"); // This string value should not be localized + ui->lvEquityList->invisibleRootItem()->addChild(item); } - // if it is in use, it_a is not equal to list.end() - if (it_a == list.constEnd() && !dontCheckExistance) - keep = false; } + } + } + + void addInvestment(const MyMoneySecurity& inv) + { + const auto id = inv.id(); + // Check that the pair does not already exist + if (ui->lvEquityList->findItems(id, Qt::MatchExactly, KMMID_COL).empty()) { + auto file = MyMoneyFile::instance(); + // check that the security is still in use + QList::const_iterator it_a; + QList list; + file->accountList(list); + for (it_a = list.constBegin(); it_a != list.constEnd(); ++it_a) { + if ((*it_a).isInvest() + && ((*it_a).currencyId() == inv.id()) + && !(*it_a).isClosed()) + break; + } + // if it is in use, it_a is not equal to list.end() + if (it_a != list.constEnd()) { + QString webID; + WebPriceQuoteSource onlineSource(inv.value("kmm-online-source")); + if (onlineSource.m_webIDBy == WebPriceQuoteSource::identifyBy::IdentificationNumber) + webID = inv.value("kmm-security-id"); // insert ISIN number... + else if (onlineSource.m_webIDBy == WebPriceQuoteSource::identifyBy::Name) + webID = inv.name(); // ...or name... + else + webID = inv.tradingSymbol(); // ...or symbol - if (keep) { QTreeWidgetItem* item = new QTreeWidgetItem(); - item->setText(WEBID_COL, symbol); - item->setText(NAME_COL, i18n("%1 units in %2", pair.first, pair.second)); + item->setForeground(WEBID_COL, KColorScheme(QPalette::Normal).foreground(KColorScheme::NormalText)); + if (webID.isEmpty()) { + webID = i18n("[No identifier]"); + item->setForeground(WEBID_COL, KColorScheme(QPalette::Normal).foreground(KColorScheme::NegativeText)); + } + item->setText(WEBID_COL, webID); + item->setText(NAME_COL, inv.name()); + MyMoneySecurity currency = file->currency(inv.tradingCurrency()); + const MyMoneyPrice &pr = file->price(id.toUtf8(), inv.tradingCurrency()); if (pr.isValid()) { - MyMoneySecurity fromCurrency = file->currency(pair.second); - MyMoneySecurity toCurrency = file->currency(pair.first); - item->setText(PRICE_COL, pr.rate(pair.second).formatMoney(fromCurrency.tradingSymbol(), toCurrency.pricePrecision())); + item->setText(PRICE_COL, pr.rate(currency.id()).formatMoney(currency.tradingSymbol(), inv.pricePrecision())); item->setText(DATE_COL, pr.date().toString(Qt::ISODate)); } item->setText(KMMID_COL, id); - item->setText(SOURCE_COL, "Yahoo Currency"); // This string value should not be localized - lvEquityList->invisibleRootItem()->addChild(item); + if (inv.value("kmm-online-quote-system") == "Finance::Quote") + item->setText(SOURCE_COL, QString("Finance::Quote %1").arg(inv.value("kmm-online-source"))); + else + item->setText(SOURCE_COL, inv.value("kmm-online-source")); + + ui->lvEquityList->invisibleRootItem()->addChild(item); + + // If this investment is denominated in a foreign currency, ensure that + // the appropriate price pair is also on the list + + if (currency.id() != file->baseCurrency().id()) { + addPricePair(MyMoneySecurityPair(currency.id(), file->baseCurrency().id()), false); + } } } } -} - -void KEquityPriceUpdateDlg::addInvestment(const MyMoneySecurity& inv) -{ - const QString id = inv.id(); - // Check that the pair does not already exist - if (lvEquityList->findItems(id, Qt::MatchExactly, KMMID_COL).empty()) { - MyMoneyFile* file = MyMoneyFile::instance(); - // check that the security is still in use - QList::const_iterator it_a; - QList list; - file->accountList(list); - for (it_a = list.constBegin(); it_a != list.constEnd(); ++it_a) { - if ((*it_a).isInvest() - && ((*it_a).currencyId() == inv.id()) - && !(*it_a).isClosed()) - break; - } - // if it is in use, it_a is not equal to list.end() - if (it_a != list.constEnd()) { - QString webID; - WebPriceQuoteSource onlineSource(inv.value("kmm-online-source")); - if (onlineSource.m_webIDBy == WebPriceQuoteSource::identifyBy::IdentificationNumber) - webID = inv.value("kmm-security-id"); // insert ISIN number... - else if (onlineSource.m_webIDBy == WebPriceQuoteSource::identifyBy::Name) - webID = inv.name(); // ...or name... - else - webID = inv.tradingSymbol(); // ...or symbol - QTreeWidgetItem* item = new QTreeWidgetItem(); - item->setForeground(WEBID_COL, KColorScheme(QPalette::Normal).foreground(KColorScheme::NormalText)); - if (webID.isEmpty()) { - webID = i18n("[No identifier]"); - item->setForeground(WEBID_COL, KColorScheme(QPalette::Normal).foreground(KColorScheme::NegativeText)); - } - item->setText(WEBID_COL, webID); - item->setText(NAME_COL, inv.name()); - MyMoneySecurity currency = file->currency(inv.tradingCurrency()); - const MyMoneyPrice &pr = file->price(id.toUtf8(), inv.tradingCurrency()); - if (pr.isValid()) { - item->setText(PRICE_COL, pr.rate(currency.id()).formatMoney(currency.tradingSymbol(), inv.pricePrecision())); - item->setText(DATE_COL, pr.date().toString(Qt::ISODate)); - } - item->setText(KMMID_COL, id); - if (inv.value("kmm-online-quote-system") == "Finance::Quote") - item->setText(SOURCE_COL, QString("Finance::Quote %1").arg(inv.value("kmm-online-source"))); - else - item->setText(SOURCE_COL, inv.value("kmm-online-source")); + KEquityPriceUpdateDlg *q_ptr; + Ui::KEquityPriceUpdateDlg *ui; + bool m_fUpdateAll; + eDialogs::UpdatePrice m_updatingPricePolicy; + WebPriceQuote m_webQuote; +}; - lvEquityList->invisibleRootItem()->addChild(item); +KEquityPriceUpdateDlg::KEquityPriceUpdateDlg(QWidget *parent, const QString& securityId) : + QDialog(parent), + d_ptr(new KEquityPriceUpdateDlgPrivate(this)) +{ + Q_D(KEquityPriceUpdateDlg); + d->init(securityId); +} - // If this investment is denominated in a foreign currency, ensure that - // the appropriate price pair is also on the list +KEquityPriceUpdateDlg::KEquityPriceUpdateDlg(QWidget *parent) : + KEquityPriceUpdateDlg(parent, QString()) +{ +} - if (currency.id() != file->baseCurrency().id()) { - addPricePair(MyMoneySecurityPair(currency.id(), file->baseCurrency().id())); - } - } - } +KEquityPriceUpdateDlg::~KEquityPriceUpdateDlg() +{ + Q_D(KEquityPriceUpdateDlg); + auto config = KSharedConfig::openConfig(); + auto grp = config->group("Equity Price Update"); + grp.writeEntry("PriceUpdatingPolicy", static_cast(d->m_updatingPricePolicy)); + grp.sync(); + delete d; } void KEquityPriceUpdateDlg::logErrorMessage(const QString& message) { logStatusMessage(QString("") + message + QString("")); } void KEquityPriceUpdateDlg::logStatusMessage(const QString& message) { - lbStatus->append(message); + Q_D(KEquityPriceUpdateDlg); + d->ui->lbStatus->append(message); } MyMoneyPrice KEquityPriceUpdateDlg::price(const QString& id) const { + Q_D(const KEquityPriceUpdateDlg); MyMoneyPrice price; - QTreeWidgetItem* item = 0; - QList foundItems = lvEquityList->findItems(id, Qt::MatchExactly, KMMID_COL); + QTreeWidgetItem* item = nullptr; + QList foundItems = d->ui->lvEquityList->findItems(id, Qt::MatchExactly, KMMID_COL); if (! foundItems.empty()) item = foundItems.at(0); if (item) { MyMoneyMoney rate(item->text(PRICE_COL)); if (!rate.isZero()) { QString id = item->text(KMMID_COL).toUtf8(); // if the ID has a space, then this is TWO ID's, so it's a currency quote if (id.contains(" ")) { QStringList ids = id.split(' ', QString::SkipEmptyParts); QString fromid = ids[0].toUtf8(); QString toid = ids[1].toUtf8(); price = MyMoneyPrice(fromid, toid, QDate().fromString(item->text(DATE_COL), Qt::ISODate), rate, item->text(SOURCE_COL)); } else // otherwise, it's a security quote { MyMoneySecurity security = MyMoneyFile::instance()->security(id); price = MyMoneyPrice(id, security.tradingCurrency(), QDate().fromString(item->text(DATE_COL), Qt::ISODate), rate, item->text(SOURCE_COL)); } } } return price; } void KEquityPriceUpdateDlg::storePrices() { + Q_D(KEquityPriceUpdateDlg); // update the new prices into the equities - MyMoneyFile* file = MyMoneyFile::instance(); + auto file = MyMoneyFile::instance(); QString name; MyMoneyFileTransaction ft; try { - for (int i = 0; i < lvEquityList->invisibleRootItem()->childCount(); ++i) { - QTreeWidgetItem* item = lvEquityList->invisibleRootItem()->child(i); + for (auto i = 0; i < d->ui->lvEquityList->invisibleRootItem()->childCount(); ++i) { + QTreeWidgetItem* item = d->ui->lvEquityList->invisibleRootItem()->child(i); // turn on signals before we modify the last entry in the list - file->blockSignals(i < lvEquityList->invisibleRootItem()->childCount() - 1); + file->blockSignals(i < d->ui->lvEquityList->invisibleRootItem()->childCount() - 1); MyMoneyMoney rate(item->text(PRICE_COL)); if (!rate.isZero()) { QString id = item->text(KMMID_COL); QString fromid; QString toid; // if the ID has a space, then this is TWO ID's, so it's a currency quote if (id.contains(QLatin1Char(' '))) { QStringList ids = id.split(QLatin1Char(' '), QString::SkipEmptyParts); fromid = ids.at(0); toid = ids.at(1); name = QString::fromLatin1("%1 --> %2").arg(fromid, toid); } else { // otherwise, it's a security quote MyMoneySecurity security = file->security(id); name = security.name(); fromid = id; toid = security.tradingCurrency(); } // TODO (Ace) Better handling of the case where there is already a price // for this date. Currently, it just overrides the old value. Really it // should check to see if the price is the same and prompt the user. file->addPrice(MyMoneyPrice(fromid, toid, QDate::fromString(item->text(DATE_COL), Qt::ISODate), rate, item->text(SOURCE_COL))); } } ft.commit(); } catch (const MyMoneyException &) { qDebug("Unable to add price information for %s", qPrintable(name)); } } void KEquityPriceUpdateDlg::slotConfigureClicked() { - EquityPriceUpdateConfDlg *dlg = new EquityPriceUpdateConfDlg(m_updatingPricePolicy); + Q_D(KEquityPriceUpdateDlg); + QPointer dlg = new EquityPriceUpdateConfDlg(d->m_updatingPricePolicy); if (dlg->exec() == QDialog::Accepted) - m_updatingPricePolicy = dlg->policy(); + d->m_updatingPricePolicy = dlg->policy(); delete dlg; } void KEquityPriceUpdateDlg::slotUpdateSelection() { + Q_D(KEquityPriceUpdateDlg); // Only enable the update button if there is a selection - btnUpdateSelected->setEnabled(false); + d->ui->btnUpdateSelected->setEnabled(false); - if (! lvEquityList->selectedItems().empty()) - btnUpdateSelected->setEnabled(true); + if (! d->ui->lvEquityList->selectedItems().empty()) + d->ui->btnUpdateSelected->setEnabled(true); } void KEquityPriceUpdateDlg::slotUpdateSelectedClicked() { + Q_D(KEquityPriceUpdateDlg); // disable sorting while the update is running to maintain the current order of items on which // the update process depends and which could be changed with sorting enabled due to the updated values - lvEquityList->setSortingEnabled(false); - QTreeWidgetItem* item = lvEquityList->invisibleRootItem()->child(0); - int skipCnt = 1; + d->ui->lvEquityList->setSortingEnabled(false); + auto item = d->ui->lvEquityList->invisibleRootItem()->child(0); + auto skipCnt = 1; while (item && !item->isSelected()) { - item = lvEquityList->invisibleRootItem()->child(skipCnt); + item = d->ui->lvEquityList->invisibleRootItem()->child(skipCnt); ++skipCnt; } - m_webQuote.setDate(m_fromDate->date(), m_toDate->date()); + d->m_webQuote.setDate(d->ui->m_fromDate->date(), d->ui->m_toDate->date()); if (item) { - prgOnlineProgress->setMaximum(1 + lvEquityList->invisibleRootItem()->childCount()); - prgOnlineProgress->setValue(skipCnt); - m_webQuote.launch(item->text(WEBID_COL), item->text(KMMID_COL), item->text(SOURCE_COL)); + d->ui->prgOnlineProgress->setMaximum(1 + d->ui->lvEquityList->invisibleRootItem()->childCount()); + d->ui->prgOnlineProgress->setValue(skipCnt); + d->m_webQuote.launch(item->text(WEBID_COL), item->text(KMMID_COL), item->text(SOURCE_COL)); } else { logErrorMessage("No security selected."); } } void KEquityPriceUpdateDlg::slotUpdateAllClicked() { + Q_D(KEquityPriceUpdateDlg); // disable sorting while the update is running to maintain the current order of items on which // the update process depends and which could be changed with sorting enabled due to the updated values - lvEquityList->setSortingEnabled(false); - QTreeWidgetItem* item = lvEquityList->invisibleRootItem()->child(0); + d->ui->lvEquityList->setSortingEnabled(false); + QTreeWidgetItem* item = d->ui->lvEquityList->invisibleRootItem()->child(0); if (item) { - prgOnlineProgress->setMaximum(1 + lvEquityList->invisibleRootItem()->childCount()); - prgOnlineProgress->setValue(1); - m_fUpdateAll = true; - m_webQuote.launch(item->text(WEBID_COL), item->text(KMMID_COL), item->text(SOURCE_COL)); + d->ui->prgOnlineProgress->setMaximum(1 + d->ui->lvEquityList->invisibleRootItem()->childCount()); + d->ui->prgOnlineProgress->setValue(1); + d->m_fUpdateAll = true; + d->m_webQuote.launch(item->text(WEBID_COL), item->text(KMMID_COL), item->text(SOURCE_COL)); } else { logErrorMessage("Security list is empty."); } } void KEquityPriceUpdateDlg::slotDateChanged() { - m_fromDate->blockSignals(true); - m_toDate->blockSignals(true); - if (m_toDate->date() > QDate::currentDate()) - m_toDate->setDate(QDate::currentDate()); - if (m_toDate->date() < m_fromDate->date()) - m_fromDate->setDate(m_toDate->date()); - m_fromDate->blockSignals(false); - m_toDate->blockSignals(false); + Q_D(KEquityPriceUpdateDlg); + d->ui->m_fromDate->blockSignals(true); + d->ui->m_toDate->blockSignals(true); + if (d->ui->m_toDate->date() > QDate::currentDate()) + d->ui->m_toDate->setDate(QDate::currentDate()); + if (d->ui->m_toDate->date() < d->ui->m_fromDate->date()) + d->ui->m_fromDate->setDate(d->ui->m_toDate->date()); + d->ui->m_fromDate->blockSignals(false); + d->ui->m_toDate->blockSignals(false); } void KEquityPriceUpdateDlg::slotQuoteFailed(const QString& _kmmID, const QString& _webID) { - QList foundItems = lvEquityList->findItems(_kmmID, Qt::MatchExactly, KMMID_COL); - QTreeWidgetItem* item = 0; + Q_D(KEquityPriceUpdateDlg); + auto foundItems = d->ui->lvEquityList->findItems(_kmmID, Qt::MatchExactly, KMMID_COL); + QTreeWidgetItem* item = nullptr; if (! foundItems.empty()) item = foundItems.at(0); // Give the user some options int result; if (_kmmID.contains(" ")) { result = KMessageBox::warningContinueCancel(this, i18n("Failed to retrieve an exchange rate for %1 from %2. It will be skipped this time.", _webID, item->text(SOURCE_COL)), i18n("Price Update Failed")); } else { result = KMessageBox::questionYesNoCancel(this, QString("%1").arg(i18n("Failed to retrieve a quote for %1 from %2. Press No to remove the online price source from this security permanently, Yes to continue updating this security during future price updates or Cancel to stop the current update operation.", _webID, item->text(SOURCE_COL))), i18n("Price Update Failed"), KStandardGuiItem::yes(), KStandardGuiItem::no()); } if (result == KMessageBox::No) { // Disable price updates for this security MyMoneyFileTransaction ft; try { // Get this security (by ID) MyMoneySecurity security = MyMoneyFile::instance()->security(_kmmID.toUtf8()); // Set the quote source to blank security.setValue("kmm-online-source", QString()); security.setValue("kmm-online-quote-system", QString()); // Re-commit the security MyMoneyFile::instance()->modifySecurity(security); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::error(this, QString("") + i18n("Cannot update security %1: %2", _webID, e.what()) + QString(""), i18n("Price Update Failed")); } } // As long as the user doesn't want to cancel, move on! if (result != KMessageBox::Cancel) { - QTreeWidgetItem* next = 0; - prgOnlineProgress->setValue(prgOnlineProgress->value() + 1); + QTreeWidgetItem* next = nullptr; + d->ui->prgOnlineProgress->setValue(d->ui->prgOnlineProgress->value() + 1); item->setSelected(false); // launch the NEXT one ... in case of m_fUpdateAll == false, we // need to parse the list to find the next selected one - next = lvEquityList->invisibleRootItem()->child(lvEquityList->invisibleRootItem()->indexOfChild(item) + 1); - if (!m_fUpdateAll) { + next = d->ui->lvEquityList->invisibleRootItem()->child(d->ui->lvEquityList->invisibleRootItem()->indexOfChild(item) + 1); + if (!d->m_fUpdateAll) { while (next && !next->isSelected()) { - prgOnlineProgress->setValue(prgOnlineProgress->value() + 1); - next = lvEquityList->invisibleRootItem()->child(lvEquityList->invisibleRootItem()->indexOfChild(next) + 1); + d->ui->prgOnlineProgress->setValue(d->ui->prgOnlineProgress->value() + 1); + next = d->ui->lvEquityList->invisibleRootItem()->child(d->ui->lvEquityList->invisibleRootItem()->indexOfChild(next) + 1); } } if (next) { - m_webQuote.launch(next->text(WEBID_COL), next->text(KMMID_COL), next->text(SOURCE_COL)); + d->m_webQuote.launch(next->text(WEBID_COL), next->text(KMMID_COL), next->text(SOURCE_COL)); } else { finishUpdate(); } } else { finishUpdate(); } } void KEquityPriceUpdateDlg::slotReceivedCSVQuote(const QString& _kmmID, const QString& _webID, MyMoneyStatement& st) { - QList foundItems = lvEquityList->findItems(_kmmID, Qt::MatchExactly, KMMID_COL); - QTreeWidgetItem* item = 0; + Q_D(KEquityPriceUpdateDlg); + auto foundItems = d->ui->lvEquityList->findItems(_kmmID, Qt::MatchExactly, KMMID_COL); + QTreeWidgetItem* item = nullptr; if (! foundItems.empty()) item = foundItems.at(0); - QTreeWidgetItem* next = 0; + QTreeWidgetItem* next = nullptr; if (item) { - MyMoneyFile *file = MyMoneyFile::instance(); + auto file = MyMoneyFile::instance(); MyMoneySecurity fromCurrency, toCurrency; if (!_kmmID.contains(QLatin1Char(' '))) { try { toCurrency = MyMoneyFile::instance()->security(_kmmID); fromCurrency = MyMoneyFile::instance()->security(toCurrency.tradingCurrency()); } catch (const MyMoneyException &) { fromCurrency = toCurrency = MyMoneySecurity(); } } else { QRegExp splitrx("([0-9a-z\\.]+)[^a-z0-9]+([0-9a-z\\.]+)", Qt::CaseInsensitive); if (splitrx.indexIn(_kmmID) != -1) { try { fromCurrency = MyMoneyFile::instance()->security(splitrx.cap(2).toUtf8()); toCurrency = MyMoneyFile::instance()->security(splitrx.cap(1).toUtf8()); } catch (const MyMoneyException &) { fromCurrency = toCurrency = MyMoneySecurity(); } } } - if (m_updatingPricePolicy != eUpdateAllPrices) { + if (d->m_updatingPricePolicy != eDialogs::UpdatePrice::All) { QStringList qSources = WebPriceQuote::quoteSources(); for (auto it = st.m_listPrices.begin(); it != st.m_listPrices.end();) { MyMoneyPrice storedPrice = file->price(toCurrency.id(), fromCurrency.id(), (*it).m_date, true); bool priceValid = storedPrice.isValid(); if (!priceValid) ++it; else { - switch(m_updatingPricePolicy) { - case eUpdateMissingPrices: + switch(d->m_updatingPricePolicy) { + case eDialogs::UpdatePrice::Missing: it = st.m_listPrices.erase(it); break; - case eUpdateDownloadedPrices: + case eDialogs::UpdatePrice::Downloaded: if (!qSources.contains(storedPrice.source())) it = st.m_listPrices.erase(it); else ++it; break; - case eUpdateSameSourcePrices: + case eDialogs::UpdatePrice::SameSource: if (storedPrice.source().compare((*it).m_sourceName) != 0) it = st.m_listPrices.erase(it); else ++it; break; - case eAsk: + case eDialogs::UpdatePrice::Ask: { int result = KMessageBox::questionYesNoCancel(this, i18n("For %1 on %2 price %3 already exists.
" "Do you want to replace it with %4?", storedPrice.from(), storedPrice.date().toString(Qt::ISODate), QString().setNum(storedPrice.rate(storedPrice.to()).toDouble(), 'g', 10), QString().setNum((*it).m_amount.toDouble(), 'g', 10)), i18n("Price Already Exists")); switch(result) { case KStandardGuiItem::Yes: ++it; break; case KStandardGuiItem::No: it = st.m_listPrices.erase(it); break; default: case KStandardGuiItem::Cancel: finishUpdate(); return; break; } break; } default: ++it; break; } } } } if (!st.m_listPrices.isEmpty()) { kmymoney->slotStatementImport(st, true); MyMoneyStatement::Price priceClass; if (st.m_listPrices.first().m_date > st.m_listPrices.last().m_date) priceClass = st.m_listPrices.first(); else priceClass = st.m_listPrices.last(); QDate latestDate = QDate::fromString(item->text(DATE_COL),Qt::ISODate); if (latestDate <= priceClass.m_date && priceClass.m_amount.isPositive()) { item->setText(PRICE_COL, priceClass.m_amount.formatMoney(fromCurrency.tradingSymbol(), toCurrency.pricePrecision())); item->setText(DATE_COL, priceClass.m_date.toString(Qt::ISODate)); item->setText(SOURCE_COL, priceClass.m_sourceName); } logStatusMessage(i18n("Price for %1 updated (id %2)", _webID, _kmmID)); // make sure to make OK button available } - buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + d->ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); - prgOnlineProgress->setValue(prgOnlineProgress->value() + 1); + d->ui->prgOnlineProgress->setValue(d->ui->prgOnlineProgress->value() + 1); item->setSelected(false); // launch the NEXT one ... in case of m_fUpdateAll == false, we // need to parse the list to find the next selected one - next = lvEquityList->invisibleRootItem()->child(lvEquityList->invisibleRootItem()->indexOfChild(item) + 1); - if (!m_fUpdateAll) { + next = d->ui->lvEquityList->invisibleRootItem()->child(d->ui->lvEquityList->invisibleRootItem()->indexOfChild(item) + 1); + if (!d->m_fUpdateAll) { while (next && !next->isSelected()) { - prgOnlineProgress->setValue(prgOnlineProgress->value() + 1); - next = lvEquityList->invisibleRootItem()->child(lvEquityList->invisibleRootItem()->indexOfChild(next) + 1); + d->ui->prgOnlineProgress->setValue(d->ui->prgOnlineProgress->value() + 1); + next = d->ui->lvEquityList->invisibleRootItem()->child(d->ui->lvEquityList->invisibleRootItem()->indexOfChild(next) + 1); } } } else { logErrorMessage(i18n("Received a price for %1 (id %2), but this symbol is not on the list. Aborting entire update.", _webID, _kmmID)); } if (next) { - m_webQuote.launch(next->text(WEBID_COL), next->text(KMMID_COL), next->text(SOURCE_COL)); + d->m_webQuote.launch(next->text(WEBID_COL), next->text(KMMID_COL), next->text(SOURCE_COL)); } else { finishUpdate(); } } void KEquityPriceUpdateDlg::slotReceivedQuote(const QString& _kmmID, const QString& _webID, const QDate& _date, const double& _price) { - QList foundItems = lvEquityList->findItems(_kmmID, Qt::MatchExactly, KMMID_COL); - QTreeWidgetItem* item = 0; + Q_D(KEquityPriceUpdateDlg); + auto foundItems = d->ui->lvEquityList->findItems(_kmmID, Qt::MatchExactly, KMMID_COL); + QTreeWidgetItem* item = nullptr; if (! foundItems.empty()) item = foundItems.at(0); QTreeWidgetItem* next = 0; if (item) { if (_price > 0.0f && _date.isValid()) { QDate date = _date; if (date > QDate::currentDate()) date = QDate::currentDate(); MyMoneyMoney price = MyMoneyMoney::ONE; QString id = _kmmID.toUtf8(); MyMoneySecurity fromCurrency, toCurrency; if (_kmmID.contains(" ") == 0) { MyMoneySecurity security = MyMoneyFile::instance()->security(id); QString factor = security.value("kmm-online-factor"); if (!factor.isEmpty()) { price = price * MyMoneyMoney(factor); } try { toCurrency = MyMoneyFile::instance()->security(id); fromCurrency = MyMoneyFile::instance()->security(toCurrency.tradingCurrency()); } catch (const MyMoneyException &) { fromCurrency = toCurrency = MyMoneySecurity(); } } else { QRegExp splitrx("([0-9a-z\\.]+)[^a-z0-9]+([0-9a-z\\.]+)", Qt::CaseInsensitive); if (splitrx.indexIn(_kmmID) != -1) { try { fromCurrency = MyMoneyFile::instance()->security(splitrx.cap(2).toUtf8()); toCurrency = MyMoneyFile::instance()->security(splitrx.cap(1).toUtf8()); } catch (const MyMoneyException &) { fromCurrency = toCurrency = MyMoneySecurity(); } } } price *= MyMoneyMoney(_price, MyMoneyMoney::precToDenom(toCurrency.pricePrecision())); item->setText(PRICE_COL, price.formatMoney(fromCurrency.tradingSymbol(), toCurrency.pricePrecision())); item->setText(DATE_COL, date.toString(Qt::ISODate)); logStatusMessage(i18n("Price for %1 updated (id %2)", _webID, _kmmID)); // make sure to make OK button available - buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + d->ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); } else { logErrorMessage(i18n("Received an invalid price for %1, unable to update.", _webID)); } - prgOnlineProgress->setValue(prgOnlineProgress->value() + 1); + d->ui->prgOnlineProgress->setValue(d->ui->prgOnlineProgress->value() + 1); item->setSelected(false); // launch the NEXT one ... in case of m_fUpdateAll == false, we // need to parse the list to find the next selected one - next = lvEquityList->invisibleRootItem()->child(lvEquityList->invisibleRootItem()->indexOfChild(item) + 1); - if (!m_fUpdateAll) { + next = d->ui->lvEquityList->invisibleRootItem()->child(d->ui->lvEquityList->invisibleRootItem()->indexOfChild(item) + 1); + if (!d->m_fUpdateAll) { while (next && !next->isSelected()) { - prgOnlineProgress->setValue(prgOnlineProgress->value() + 1); - next = lvEquityList->invisibleRootItem()->child(lvEquityList->invisibleRootItem()->indexOfChild(next) + 1); + d->ui->prgOnlineProgress->setValue(d->ui->prgOnlineProgress->value() + 1); + next = d->ui->lvEquityList->invisibleRootItem()->child(d->ui->lvEquityList->invisibleRootItem()->indexOfChild(next) + 1); } } } else { logErrorMessage(i18n("Received a price for %1 (id %2), but this symbol is not on the list. Aborting entire update.", _webID, _kmmID)); } if (next) { - m_webQuote.launch(next->text(WEBID_COL), next->text(KMMID_COL), next->text(SOURCE_COL)); + d->m_webQuote.launch(next->text(WEBID_COL), next->text(KMMID_COL), next->text(SOURCE_COL)); } else { finishUpdate(); } } void KEquityPriceUpdateDlg::finishUpdate() { + Q_D(KEquityPriceUpdateDlg); // we've run past the end, reset to the default value. - m_fUpdateAll = false; + d->m_fUpdateAll = false; // force progress bar to show 100% - prgOnlineProgress->setValue(prgOnlineProgress->maximum()); + d->ui->prgOnlineProgress->setValue(d->ui->prgOnlineProgress->maximum()); // re-enable the sorting that was disabled during the update process - lvEquityList->setSortingEnabled(true); + d->ui->lvEquityList->setSortingEnabled(true); } // Make sure, that these definitions are only used within this file // this does not seem to be necessary, but when building RPMs the // build option 'final' is used and all CPP files are concatenated. // So it could well be, that in another CPP file these definitions // are also used. #undef WEBID_COL #undef NAME_COL #undef PRICE_COL #undef DATE_COL #undef KMMID_COL #undef SOURCE_COL diff --git a/kmymoney/dialogs/kequitypriceupdatedlg.h b/kmymoney/dialogs/kequitypriceupdatedlg.h index 73cb1ddab..3d5509c61 100644 --- a/kmymoney/dialogs/kequitypriceupdatedlg.h +++ b/kmymoney/dialogs/kequitypriceupdatedlg.h @@ -1,89 +1,86 @@ /*************************************************************************** kequitypriceupdatedlg.h - description ------------------- begin : Tuesday June 22nd, 2004 copyright : (C) 2000-2004 by Kevin Tambascio email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KEQUITYPRICEUPDATEDLG_H #define KEQUITYPRICEUPDATEDLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "webpricequote.h" -#include "mymoneyprice.h" -#include "kequitypriceupdateconfdlg.h" -#include "ui_kequitypriceupdatedlgdecl.h" - class MyMoneySecurity; +class MyMoneyStatement; +class MyMoneyPrice; + +typedef QPair MyMoneySecurityPair; +typedef QMap MyMoneyPriceEntries; +typedef QMap MyMoneyPriceList; /** * @author Kevin Tambascio & Ace Jones */ -class MyMoneyStatement; -class KEquityPriceUpdateDlgDecl : public QDialog, public Ui::KEquityPriceUpdateDlgDecl -{ -public: - KEquityPriceUpdateDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; -class KEquityPriceUpdateDlg : public KEquityPriceUpdateDlgDecl +class KEquityPriceUpdateDlgPrivate; +class KEquityPriceUpdateDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KEquityPriceUpdateDlg) + public: - explicit KEquityPriceUpdateDlg(QWidget *parent, const QString& securityId = QString()); + explicit KEquityPriceUpdateDlg(QWidget *parent, const QString& securityId); + explicit KEquityPriceUpdateDlg(QWidget *parent); ~KEquityPriceUpdateDlg(); void storePrices(); MyMoneyPrice price(const QString& id) const; protected slots: void slotConfigureClicked(); void slotUpdateSelectedClicked(); void slotUpdateAllClicked(); void slotUpdateSelection(); void slotDateChanged(); void logStatusMessage(const QString&); void logErrorMessage(const QString&); void slotReceivedCSVQuote(const QString& _kmmID, const QString& _webID, MyMoneyStatement& st); void slotReceivedQuote(const QString& _kmmID, const QString& _webID, const QDate&, const double&); void slotQuoteFailed(const QString& _kmmID, const QString& _webID); protected: - void addPricePair(const MyMoneySecurityPair& pair, bool dontCheckExistance = false); void addInvestment(const MyMoneySecurity& inv); void finishUpdate(); private: - bool m_fUpdateAll; - updatingPricePolicyE m_updatingPricePolicy; - WebPriceQuote m_webQuote; + KEquityPriceUpdateDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KEquityPriceUpdateDlg) + }; #endif // KEQUITYPRICEUPDATEDLG_H diff --git a/kmymoney/dialogs/kequitypriceupdatedlgdecl.ui b/kmymoney/dialogs/kequitypriceupdatedlg.ui similarity index 83% rename from kmymoney/dialogs/kequitypriceupdatedlgdecl.ui rename to kmymoney/dialogs/kequitypriceupdatedlg.ui index 4982c563f..ea17a2d6e 100644 --- a/kmymoney/dialogs/kequitypriceupdatedlgdecl.ui +++ b/kmymoney/dialogs/kequitypriceupdatedlg.ui @@ -1,163 +1,197 @@ Kevin Tambascio <ktambascio@users.sourceforge.net> - KEquityPriceUpdateDlgDecl - + KEquityPriceUpdateDlg + 0 0 537 482 Update Stock and Currency Prices 350 0 List of known Equities, and the date they were last updated on. QFrame::StyledPanel QFrame::Plain true false true true 1 From To Configure Qt::Horizontal QSizePolicy::Expanding 21 20 Update All Update Selected Status: false true QDialogButtonBox::Cancel|QDialogButtonBox::Ok KTextEdit QTextEdit
ktextedit.h
kMyMoneyDateInput QWidget
kmymoneydateinput.h
+ 1
- + + + buttonBox + accepted() + KEquityPriceUpdateDlg + accept() + + + 268 + 458 + + + 268 + 240 + + + + + buttonBox + rejected() + KEquityPriceUpdateDlg + reject() + + + 268 + 458 + + + 268 + 240 + + + +
diff --git a/kmymoney/dialogs/kfindtransactiondlg.cpp b/kmymoney/dialogs/kfindtransactiondlg.cpp index dd7f99f7b..a03524655 100644 --- a/kmymoney/dialogs/kfindtransactiondlg.cpp +++ b/kmymoney/dialogs/kfindtransactiondlg.cpp @@ -1,937 +1,464 @@ /*************************************************************************** kfindtransactiondlg.cpp ------------------- copyright : (C) 2003, 2007 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ -#include "config-kmymoney.h" - #include "kfindtransactiondlg.h" +#include "kfindtransactiondlg_p.h" // ---------------------------------------------------------------------------- // QT Includes #include -#include #include #include -#include #include #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include -#include -#include #include // ---------------------------------------------------------------------------- // Project Includes +#include "mymoneysplit.h" +#include "mymoneytransaction.h" +#include "mymoneytransactionfilter.h" #include "kmymoneyedit.h" -#include "mymoneyfile.h" -#include "mymoneypayee.h" -#include "mymoneytag.h" #include "kmymoneyglobalsettings.h" #include "register.h" #include "transaction.h" #include "daterangedlg.h" -#include "ui_kfindtransactiondlgdecl.h" +#include "ui_kfindtransactiondlg.h" #include "ui_ksortoptiondlg.h" -enum ItemRoles { - ItemIdRole = Qt::UserRole -}; - -struct KSortOptionDlg::Private { - Ui::KSortOptionDlg ui; -}; -KSortOptionDlg::KSortOptionDlg(QWidget *parent) - : QDialog(parent), d(new Private) +KSortOptionDlg::KSortOptionDlg(QWidget *parent) : + QDialog(parent), + ui(new Ui::KSortOptionDlg) { - d->ui.setupUi(this); - init(); + ui->setupUi(this); } KSortOptionDlg::~KSortOptionDlg() { - delete d; -} - -void KSortOptionDlg::init() -{ + delete ui; } void KSortOptionDlg::setSortOption(const QString& option, const QString& def) { if (option.isEmpty()) { - d->ui.m_sortOption->setSettings(def); - d->ui.m_useDefault->setChecked(true); + ui->m_sortOption->setSettings(def); + ui->m_useDefault->setChecked(true); } else { - d->ui.m_sortOption->setSettings(option); - d->ui.m_useDefault->setChecked(false); + ui->m_sortOption->setSettings(option); + ui->m_useDefault->setChecked(false); } } QString KSortOptionDlg::sortOption() const { QString rc; - if (!d->ui.m_useDefault->isChecked()) { - rc = d->ui.m_sortOption->settings(); + if (!ui->m_useDefault->isChecked()) { + rc = ui->m_sortOption->settings(); } return rc; } void KSortOptionDlg::hideDefaultButton() { - d->ui.m_useDefault->hide(); + ui->m_useDefault->hide(); } - -KFindTransactionDlg::KFindTransactionDlg(QWidget *parent, bool withEquityAccounts) - : QDialog(parent) - , m_needReload(false) - , m_ui(new Ui::KFindTransactionDlgDecl) +KFindTransactionDlg::KFindTransactionDlg(QWidget *parent, bool withEquityAccounts) : + QDialog(parent), + d_ptr(new KFindTransactionDlgPrivate(this)) { - m_ui->setupUi(this); - m_dateRange = new DateRangeDlg; - m_ui->dateRangeLayout->insertWidget(0, m_dateRange); - - m_ui->ButtonGroup1->setId(m_ui->m_amountButton, 0); - m_ui->ButtonGroup1->setId(m_ui->m_amountRangeButton, 1); - - m_ui->m_register->installEventFilter(this); - m_ui->m_tabWidget->setTabEnabled(m_ui->m_tabWidget->indexOf(m_ui->m_resultPage), false); - - // 'cause we don't have a separate setupTextPage - connect(m_ui->m_textEdit, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateSelections())); - // if return is pressed trigger a search (slotSearch checks if it's possible to perform the search) - connect(m_ui->m_textEdit, SIGNAL(returnPressed()), this, SLOT(slotSearch())); - // in case the date selection changes, we update the selection - connect(m_dateRange, SIGNAL(rangeChanged()), this, SLOT(slotUpdateSelections())); - - setupAccountsPage(withEquityAccounts); - setupCategoriesPage(); - setupAmountPage(); - setupPayeesPage(); - setupTagsPage(); - setupDetailsPage(); - - // We don't need to add the default into the list (see ::slotShowHelp() why) - // m_helpAnchor[m_ui->m_textTab] = QLatin1String("details.search"); - m_helpAnchor[m_ui->m_accountTab] = QLatin1String("details.search.account"); - m_helpAnchor[m_ui->m_dateTab] = QLatin1String("details.search.date"); - m_helpAnchor[m_ui->m_amountTab] = QLatin1String("details.search.amount"); - m_helpAnchor[m_ui->m_categoryTab] = QLatin1String("details.search.category"); - m_helpAnchor[m_ui->m_payeeTab] = QLatin1String("details.search.payee"); - m_helpAnchor[m_ui->m_tagTab] = QLatin1String("details.search.tag"); //FIXME-ALEX update Help - m_helpAnchor[m_ui->m_detailsTab] = QLatin1String("details.search.details"); - - // setup the register - QList cols; - cols << KMyMoneyRegister::DateColumn; - cols << KMyMoneyRegister::AccountColumn; - cols << KMyMoneyRegister::DetailColumn; - cols << KMyMoneyRegister::ReconcileFlagColumn; - cols << KMyMoneyRegister::PaymentColumn; - cols << KMyMoneyRegister::DepositColumn; - m_ui->m_register->setupRegister(MyMoneyAccount(), cols); - m_ui->m_register->setSelectionMode(QTableWidget::SingleSelection); - - connect(m_ui->m_register, SIGNAL(editTransaction()), this, SLOT(slotSelectTransaction())); - connect(m_ui->m_register->horizontalHeader(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotSortOptions())); - - slotUpdateSelections(); - - // setup the connections - connect(m_ui->buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotSearch())); - connect(m_ui->buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), this, SLOT(slotReset())); - connect(m_ui->buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), m_ui->m_accountsView, SLOT(slotSelectAllAccounts())); - connect(m_ui->buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), m_ui->m_categoriesView, SLOT(slotSelectAllAccounts())); - connect(m_ui->buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(deleteLater())); - connect(m_ui->buttonBox->button(QDialogButtonBox::Help), SIGNAL(clicked()), this, SLOT(slotShowHelp())); - - // only allow searches when a selection has been made - m_ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); - KGuiItem::assign(m_ui->buttonBox->button(QDialogButtonBox::Apply), KStandardGuiItem::find()); - m_ui->buttonBox->button(QDialogButtonBox::Apply)->setToolTip(i18nc("@info:tooltip for find transaction apply button", "Search transactions")); - connect(this, SIGNAL(selectionNotEmpty(bool)), m_ui->buttonBox->button(QDialogButtonBox::Apply), SLOT(setEnabled(bool))); - - // get signal about engine changes - connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotRefreshView())); - - slotUpdateSelections(); + Q_D(KFindTransactionDlg); + d->init(withEquityAccounts); +} - m_ui->m_textEdit->setFocus(); +KFindTransactionDlg::KFindTransactionDlg(KFindTransactionDlgPrivate &dd, QWidget *parent, bool withEquityAccounts) : + QDialog(parent), + d_ptr(&dd) +{ + Q_D(KFindTransactionDlg); + d->init(withEquityAccounts); } KFindTransactionDlg::~KFindTransactionDlg() { - delete m_ui; + Q_D(KFindTransactionDlg); + delete d; } void KFindTransactionDlg::slotReset() { - m_ui->m_textEdit->setText(QString()); - m_ui->m_regExp->setChecked(false); - m_ui->m_caseSensitive->setChecked(false); - m_ui->m_textNegate->setCurrentItem(0); - - m_ui->m_amountEdit->setEnabled(true); - m_ui->m_amountFromEdit->setEnabled(false); - m_ui->m_amountToEdit->setEnabled(false); - m_ui->m_amountEdit->loadText(QString()); - m_ui->m_amountFromEdit->loadText(QString()); - m_ui->m_amountToEdit->loadText(QString()); - m_ui->m_amountButton->setChecked(true); - m_ui->m_amountRangeButton->setChecked(false); - - m_ui->m_emptyPayeesButton->setChecked(false); - selectAllItems(m_ui->m_payeesView, true); - - m_ui->m_emptyTagsButton->setChecked(false); - selectAllItems(m_ui->m_tagsView, true); - - m_ui->m_typeBox->setCurrentIndex((int)eMyMoney::TransactionFilter::Type::All); - m_ui->m_stateBox->setCurrentIndex((int)eMyMoney::TransactionFilter::State::All); - m_ui->m_validityBox->setCurrentIndex((int)eMyMoney::TransactionFilter::Validity::Any); - - m_ui->m_nrEdit->setEnabled(true); - m_ui->m_nrFromEdit->setEnabled(false); - m_ui->m_nrToEdit->setEnabled(false); - m_ui->m_nrEdit->setText(QString()); - m_ui->m_nrFromEdit->setText(QString()); - m_ui->m_nrToEdit->setText(QString()); - m_ui->m_nrButton->setChecked(true); - m_ui->m_nrRangeButton->setChecked(false); - - m_ui->m_tabWidget->setTabEnabled(m_ui->m_tabWidget->indexOf(m_ui->m_resultPage), false); - m_ui->m_tabWidget->setCurrentIndex(m_ui->m_tabWidget->indexOf(m_ui->m_criteriaTab)); + Q_D(KFindTransactionDlg); + d->ui->m_textEdit->setText(QString()); + d->ui->m_regExp->setChecked(false); + d->ui->m_caseSensitive->setChecked(false); + d->ui->m_textNegate->setCurrentItem(0); + + d->ui->m_amountEdit->setEnabled(true); + d->ui->m_amountFromEdit->setEnabled(false); + d->ui->m_amountToEdit->setEnabled(false); + d->ui->m_amountEdit->loadText(QString()); + d->ui->m_amountFromEdit->loadText(QString()); + d->ui->m_amountToEdit->loadText(QString()); + d->ui->m_amountButton->setChecked(true); + d->ui->m_amountRangeButton->setChecked(false); + + d->ui->m_emptyPayeesButton->setChecked(false); + d->selectAllItems(d->ui->m_payeesView, true); + + d->ui->m_emptyTagsButton->setChecked(false); + d->selectAllItems(d->ui->m_tagsView, true); + + d->ui->m_typeBox->setCurrentIndex((int)eMyMoney::TransactionFilter::Type::All); + d->ui->m_stateBox->setCurrentIndex((int)eMyMoney::TransactionFilter::State::All); + d->ui->m_validityBox->setCurrentIndex((int)eMyMoney::TransactionFilter::Validity::Any); + + d->ui->m_nrEdit->setEnabled(true); + d->ui->m_nrFromEdit->setEnabled(false); + d->ui->m_nrToEdit->setEnabled(false); + d->ui->m_nrEdit->setText(QString()); + d->ui->m_nrFromEdit->setText(QString()); + d->ui->m_nrToEdit->setText(QString()); + d->ui->m_nrButton->setChecked(true); + d->ui->m_nrRangeButton->setChecked(false); + + d->ui->m_tabWidget->setTabEnabled(d->ui->m_tabWidget->indexOf(d->ui->m_resultPage), false); + d->ui->m_tabWidget->setCurrentIndex(d->ui->m_tabWidget->indexOf(d->ui->m_criteriaTab)); // the following call implies a call to slotUpdateSelections, // that's why we call it last - m_dateRange->slotReset(); + d->m_dateRange->slotReset(); slotUpdateSelections(); } void KFindTransactionDlg::slotUpdateSelections() { + Q_D(KFindTransactionDlg); QString txt; // Text tab - if (!m_ui->m_textEdit->text().isEmpty()) { + if (!d->ui->m_textEdit->text().isEmpty()) { if (!txt.isEmpty()) txt += ", "; txt += i18n("Text"); - m_ui->m_regExp->setEnabled(QRegExp(m_ui->m_textEdit->text()).isValid()); + d->ui->m_regExp->setEnabled(QRegExp(d->ui->m_textEdit->text()).isValid()); } else - m_ui->m_regExp->setEnabled(false); + d->ui->m_regExp->setEnabled(false); - m_ui->m_caseSensitive->setEnabled(!m_ui->m_textEdit->text().isEmpty()); - m_ui->m_textNegate->setEnabled(!m_ui->m_textEdit->text().isEmpty()); + d->ui->m_caseSensitive->setEnabled(!d->ui->m_textEdit->text().isEmpty()); + d->ui->m_textNegate->setEnabled(!d->ui->m_textEdit->text().isEmpty()); // Account tab - if (!m_ui->m_accountsView->allItemsSelected()) { + if (!d->ui->m_accountsView->allItemsSelected()) { if (!txt.isEmpty()) txt += ", "; txt += i18n("Account"); } - if (m_dateRange->dateRange() != eMyMoney::TransactionFilter::Date::All) { + if (d->m_dateRange->dateRange() != eMyMoney::TransactionFilter::Date::All) { if (!txt.isEmpty()) txt += ", "; txt += i18n("Date"); } // Amount tab - if ((m_ui->m_amountButton->isChecked() && m_ui->m_amountEdit->isValid()) - || (m_ui->m_amountRangeButton->isChecked() - && (m_ui->m_amountFromEdit->isValid() || m_ui->m_amountToEdit->isValid()))) { + if ((d->ui->m_amountButton->isChecked() && d->ui->m_amountEdit->isValid()) + || (d->ui->m_amountRangeButton->isChecked() + && (d->ui->m_amountFromEdit->isValid() || d->ui->m_amountToEdit->isValid()))) { if (!txt.isEmpty()) txt += ", "; txt += i18n("Amount"); } // Categories tab - if (!m_ui->m_categoriesView->allItemsSelected()) { + if (!d->ui->m_categoriesView->allItemsSelected()) { if (!txt.isEmpty()) txt += ", "; txt += i18n("Category"); } // Tags tab - if (!allItemsSelected(m_ui->m_tagsView) - || m_ui->m_emptyTagsButton->isChecked()) { + if (!d->allItemsSelected(d->ui->m_tagsView) + || d->ui->m_emptyTagsButton->isChecked()) { if (!txt.isEmpty()) txt += ", "; txt += i18n("Tags"); } - m_ui->m_tagsView->setEnabled(!m_ui->m_emptyTagsButton->isChecked()); + d->ui->m_tagsView->setEnabled(!d->ui->m_emptyTagsButton->isChecked()); // Payees tab - if (!allItemsSelected(m_ui->m_payeesView) - || m_ui->m_emptyPayeesButton->isChecked()) { + if (!d->allItemsSelected(d->ui->m_payeesView) + || d->ui->m_emptyPayeesButton->isChecked()) { if (!txt.isEmpty()) txt += ", "; txt += i18n("Payees"); } - m_ui->m_payeesView->setEnabled(!m_ui->m_emptyPayeesButton->isChecked()); + d->ui->m_payeesView->setEnabled(!d->ui->m_emptyPayeesButton->isChecked()); // Details tab - if (m_ui->m_typeBox->currentIndex() != 0 - || m_ui->m_stateBox->currentIndex() != 0 - || m_ui->m_validityBox->currentIndex() != 0 - || (m_ui->m_nrButton->isChecked() && m_ui->m_nrEdit->text().length() != 0) - || (m_ui->m_nrRangeButton->isChecked() - && (m_ui->m_nrFromEdit->text().length() != 0 || m_ui->m_nrToEdit->text().length() != 0))) { + if (d->ui->m_typeBox->currentIndex() != 0 + || d->ui->m_stateBox->currentIndex() != 0 + || d->ui->m_validityBox->currentIndex() != 0 + || (d->ui->m_nrButton->isChecked() && d->ui->m_nrEdit->text().length() != 0) + || (d->ui->m_nrRangeButton->isChecked() + && (d->ui->m_nrFromEdit->text().length() != 0 || d->ui->m_nrToEdit->text().length() != 0))) { if (!txt.isEmpty()) txt += ", "; txt += i18n("Details"); } //Show a warning about transfers if Categories are filtered - bug #1523508 - if (!m_ui->m_categoriesView->allItemsSelected()) { - m_ui->m_transferWarning->setText(i18n("Warning: Filtering by Category will exclude all transfers from the results.")); + if (!d->ui->m_categoriesView->allItemsSelected()) { + d->ui->m_transferWarning->setText(i18n("Warning: Filtering by Category will exclude all transfers from the results.")); } else { - m_ui->m_transferWarning->setText(""); + d->ui->m_transferWarning->setText(""); } // disable the search button if no selection is made emit selectionNotEmpty(!txt.isEmpty()); if (txt.isEmpty()) { txt = i18nc("No selection", "(None)"); } - m_ui->m_selectedCriteria->setText(i18n("Current selections: %1", txt)); -} - -bool KFindTransactionDlg::allItemsSelected(const QTreeWidgetItem *item) const -{ - QTreeWidgetItem* it_v; - - for (int i = 0; i < item->childCount(); ++i) { - it_v = item->child(i); - if (!(it_v->checkState(0) == Qt::Checked && allItemsSelected(it_v))) { - return false; - } - } - return true; -} - -bool KFindTransactionDlg::allItemsSelected(const QTreeWidget* view) const -{ - QTreeWidgetItem* it_v; - - for (int i = 0; i < view->invisibleRootItem()->childCount(); ++i) { - it_v = view->invisibleRootItem()->child(i); - if (it_v->flags() & Qt::ItemIsUserCheckable) { - if (!(it_v->checkState(0) == Qt::Checked && allItemsSelected(it_v))) { - return false; - } else { - if (!allItemsSelected(it_v)) - return false; - } - } - } - return true; -} - -void KFindTransactionDlg::setupAccountsPage(bool withEquityAccounts) -{ - m_ui->m_accountsView->setSelectionMode(QTreeWidget::MultiSelection); - AccountSet accountSet; - accountSet.addAccountGroup(eMyMoney::Account::Asset); - accountSet.addAccountGroup(eMyMoney::Account::Liability); - - if (withEquityAccounts) - accountSet.addAccountGroup(eMyMoney::Account::Equity); - - //set the accountset to show closed account if the settings say so - accountSet.setHideClosedAccounts(KMyMoneyGlobalSettings::hideClosedAccounts()); - accountSet.load(m_ui->m_accountsView); - connect(m_ui->m_accountsView, SIGNAL(stateChanged()), this, SLOT(slotUpdateSelections())); -} - -void KFindTransactionDlg::selectAllItems(QTreeWidget* view, const bool state) -{ - QTreeWidgetItem* it_v; - - for (int i = 0; i < view->invisibleRootItem()->childCount(); ++i) { - it_v = view->invisibleRootItem()->child(i); - if (it_v->flags() & Qt::ItemIsUserCheckable) { - it_v->setCheckState(0, state ? Qt::Checked : Qt::Unchecked); - } - selectAllSubItems(it_v, state); - } - slotUpdateSelections(); -} - -void KFindTransactionDlg::selectItems(QTreeWidget* view, const QStringList& list, const bool state) -{ - QTreeWidgetItem* it_v; - - for (int i = 0; i < view->invisibleRootItem()->childCount(); ++i) { - it_v = view->invisibleRootItem()->child(i); - QVariant idData = it_v->data(0, ItemIdRole); - if (it_v->flags() & Qt::ItemIsUserCheckable && list.contains(idData.toString())) { - it_v->setCheckState(0, state ? Qt::Checked : Qt::Unchecked); - } - selectSubItems(it_v, list, state); - } - - slotUpdateSelections(); -} - -void KFindTransactionDlg::setupCategoriesPage() -{ - m_ui->m_categoriesView->setSelectionMode(QTreeWidget::MultiSelection); - AccountSet categorySet; - categorySet.addAccountGroup(eMyMoney::Account::Income); - categorySet.addAccountGroup(eMyMoney::Account::Expense); - categorySet.load(m_ui->m_categoriesView); - connect(m_ui->m_categoriesView, SIGNAL(stateChanged()), this, SLOT(slotUpdateSelections())); -} - -void KFindTransactionDlg::selectAllSubItems(QTreeWidgetItem* item, const bool state) -{ - QTreeWidgetItem* it_v; - - for (int i = 0; i < item->childCount(); ++i) { - it_v = item->child(i); - it_v->setCheckState(0, state ? Qt::Checked : Qt::Unchecked); - selectAllSubItems(it_v, state); - } -} - -void KFindTransactionDlg::selectSubItems(QTreeWidgetItem* item, const QStringList& list, const bool state) -{ - QTreeWidgetItem* it_v; - - for (int i = 0; i < item->childCount(); ++i) { - it_v = item->child(i); - QVariant idData = it_v->data(0, ItemIdRole); - if (list.contains(idData.toString())) - it_v->setCheckState(0, state ? Qt::Checked : Qt::Unchecked); - selectSubItems(it_v, list, state); - } -} - -void KFindTransactionDlg::setupAmountPage() -{ - connect(m_ui->m_amountButton, SIGNAL(clicked()), this, SLOT(slotAmountSelected())); - connect(m_ui->m_amountRangeButton, SIGNAL(clicked()), this, SLOT(slotAmountRangeSelected())); - - connect(m_ui->m_amountEdit, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateSelections())); - connect(m_ui->m_amountFromEdit, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateSelections())); - connect(m_ui->m_amountToEdit, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateSelections())); - - m_ui->m_amountButton->setChecked(true); - slotAmountSelected(); + d->ui->m_selectedCriteria->setText(i18n("Current selections: %1", txt)); } void KFindTransactionDlg::slotAmountSelected() { - m_ui->m_amountEdit->setEnabled(true); - m_ui->m_amountFromEdit->setEnabled(false); - m_ui->m_amountToEdit->setEnabled(false); + Q_D(KFindTransactionDlg); + d->ui->m_amountEdit->setEnabled(true); + d->ui->m_amountFromEdit->setEnabled(false); + d->ui->m_amountToEdit->setEnabled(false); slotUpdateSelections(); } void KFindTransactionDlg::slotAmountRangeSelected() { - m_ui->m_amountEdit->setEnabled(false); - m_ui->m_amountFromEdit->setEnabled(true); - m_ui->m_amountToEdit->setEnabled(true); + Q_D(KFindTransactionDlg); + d->ui->m_amountEdit->setEnabled(false); + d->ui->m_amountFromEdit->setEnabled(true); + d->ui->m_amountToEdit->setEnabled(true); slotUpdateSelections(); } -void KFindTransactionDlg::setupPayeesPage() -{ - m_ui->m_payeesView->setSelectionMode(QAbstractItemView::SingleSelection); - m_ui->m_payeesView->header()->hide(); - m_ui->m_payeesView->setAlternatingRowColors(true); - - loadPayees(); - - m_ui->m_payeesView->sortItems(0, Qt::AscendingOrder); - m_ui->m_emptyPayeesButton->setCheckState(Qt::Unchecked); - - connect(m_ui->m_allPayeesButton, SIGNAL(clicked()), this, SLOT(slotSelectAllPayees())); - connect(m_ui->m_clearPayeesButton, SIGNAL(clicked()), this, SLOT(slotDeselectAllPayees())); - connect(m_ui->m_emptyPayeesButton, SIGNAL(stateChanged(int)), this, SLOT(slotUpdateSelections())); - connect(m_ui->m_payeesView, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(slotUpdateSelections())); -} - -void KFindTransactionDlg::loadPayees() -{ - MyMoneyFile* file = MyMoneyFile::instance(); - QList list; - QList::Iterator it_l; - - list = file->payeeList(); - // load view - for (it_l = list.begin(); it_l != list.end(); ++it_l) { - QTreeWidgetItem* item = new QTreeWidgetItem(m_ui->m_payeesView); - item->setText(0, (*it_l).name()); - item->setData(0, ItemIdRole, (*it_l).id()); - item->setCheckState(0, Qt::Checked); - } -} void KFindTransactionDlg::slotSelectAllPayees() { - selectAllItems(m_ui->m_payeesView, true); + Q_D(KFindTransactionDlg); + d->selectAllItems(d->ui->m_payeesView, true); } void KFindTransactionDlg::slotDeselectAllPayees() { - selectAllItems(m_ui->m_payeesView, false); -} - -void KFindTransactionDlg::setupTagsPage() -{ - m_ui->m_tagsView->setSelectionMode(QAbstractItemView::SingleSelection); - m_ui->m_tagsView->header()->hide(); - m_ui->m_tagsView->setAlternatingRowColors(true); - - loadTags(); - - m_ui->m_tagsView->sortItems(0, Qt::AscendingOrder); - m_ui->m_emptyTagsButton->setCheckState(Qt::Unchecked); - - connect(m_ui->m_allTagsButton, SIGNAL(clicked()), this, SLOT(slotSelectAllTags())); - connect(m_ui->m_clearTagsButton, SIGNAL(clicked()), this, SLOT(slotDeselectAllTags())); - connect(m_ui->m_emptyTagsButton, SIGNAL(stateChanged(int)), this, SLOT(slotUpdateSelections())); - connect(m_ui->m_tagsView, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(slotUpdateSelections())); + Q_D(KFindTransactionDlg); + d->selectAllItems(d->ui->m_payeesView, false); } -void KFindTransactionDlg::loadTags() -{ - MyMoneyFile* file = MyMoneyFile::instance(); - QList list; - QList::Iterator it_l; - - list = file->tagList(); - // load view - for (it_l = list.begin(); it_l != list.end(); ++it_l) { - QTreeWidgetItem* item = new QTreeWidgetItem(m_ui->m_tagsView); - item->setText(0, (*it_l).name()); - item->setData(0, ItemIdRole, (*it_l).id()); - item->setCheckState(0, Qt::Checked); - } -} void KFindTransactionDlg::slotSelectAllTags() { - selectAllItems(m_ui->m_tagsView, true); + Q_D(KFindTransactionDlg); + d->selectAllItems(d->ui->m_tagsView, true); } void KFindTransactionDlg::slotDeselectAllTags() { - selectAllItems(m_ui->m_tagsView, false); -} - -void KFindTransactionDlg::setupDetailsPage() -{ - connect(m_ui->m_typeBox, SIGNAL(activated(int)), this, SLOT(slotUpdateSelections())); - connect(m_ui->m_stateBox, SIGNAL(activated(int)), this, SLOT(slotUpdateSelections())); - connect(m_ui->m_validityBox, SIGNAL(activated(int)), this, SLOT(slotUpdateSelections())); - - connect(m_ui->m_nrButton, SIGNAL(clicked()), this, SLOT(slotNrSelected())); - connect(m_ui->m_nrRangeButton, SIGNAL(clicked()), this, SLOT(slotNrRangeSelected())); - connect(m_ui->m_nrEdit, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateSelections())); - connect(m_ui->m_nrFromEdit, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateSelections())); - connect(m_ui->m_nrToEdit, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateSelections())); - - m_ui->m_nrButton->setChecked(true); - slotNrSelected(); + Q_D(KFindTransactionDlg); + d->selectAllItems(d->ui->m_tagsView, false); } void KFindTransactionDlg::slotNrSelected() { - m_ui->m_nrEdit->setEnabled(true); - m_ui->m_nrFromEdit->setEnabled(false); - m_ui->m_nrToEdit->setEnabled(false); + Q_D(KFindTransactionDlg); + d->ui->m_nrEdit->setEnabled(true); + d->ui->m_nrFromEdit->setEnabled(false); + d->ui->m_nrToEdit->setEnabled(false); slotUpdateSelections(); } void KFindTransactionDlg::slotNrRangeSelected() { - m_ui->m_nrEdit->setEnabled(false); - m_ui->m_nrFromEdit->setEnabled(true); - m_ui->m_nrToEdit->setEnabled(true); + Q_D(KFindTransactionDlg); + d->ui->m_nrEdit->setEnabled(false); + d->ui->m_nrFromEdit->setEnabled(true); + d->ui->m_nrToEdit->setEnabled(true); slotUpdateSelections(); } -void KFindTransactionDlg::addItemToFilter(const opTypeE op, const QString& id) -{ - switch (op) { - case addAccountToFilter: - m_filter.addAccount(id); - break; - case addCategoryToFilter: - m_filter.addCategory(id); - break; - case addPayeeToFilter: - m_filter.addPayee(id); - break; - case addTagToFilter: - m_filter.addTag(id); - break; - } -} - -void KFindTransactionDlg::scanCheckListItems(const QTreeWidgetItem* item, const opTypeE op) -{ - QTreeWidgetItem* it_v; - - for (int i = 0; i < item->childCount(); ++i) { - it_v = item->child(i); - QVariant idData = it_v->data(0, ItemIdRole); - if (it_v->flags() & Qt::ItemIsUserCheckable) { - if (it_v->checkState(0) == Qt::Checked) - addItemToFilter(op, idData.toString()); - } - scanCheckListItems(it_v, op); - } -} - -void KFindTransactionDlg::scanCheckListItems(const QTreeWidget* view, const opTypeE op) -{ - QTreeWidgetItem* it_v; - - for (int i = 0; i < view->invisibleRootItem()->childCount(); ++i) { - it_v = view->invisibleRootItem()->child(i); - QVariant idData = it_v->data(0, ItemIdRole); - if (it_v->flags() & Qt::ItemIsUserCheckable) { - if (it_v->checkState(0) == Qt::Checked) { - addItemToFilter(op, idData.toString()); - } - } - scanCheckListItems(it_v, op); - } -} - -void KFindTransactionDlg::setupFilter() -{ - m_filter.clear(); - - // Text tab - if (!m_ui->m_textEdit->text().isEmpty()) { - QRegExp exp(m_ui->m_textEdit->text(), m_ui->m_caseSensitive->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive, !m_ui->m_regExp->isChecked() ? QRegExp::Wildcard : QRegExp::RegExp); - m_filter.setTextFilter(exp, m_ui->m_textNegate->currentIndex() != 0); - } - - // Account tab - if (!m_ui->m_accountsView->allItemsSelected()) { - // retrieve a list of selected accounts - QStringList list; - m_ui->m_accountsView->selectedItems(list); - - // if we're not in expert mode, we need to make sure - // that all stock accounts for the selected investment - // account are also selected - if (!KMyMoneyGlobalSettings::expertMode()) { - QStringList missing; - QStringList::const_iterator it_a, it_b; - for (it_a = list.constBegin(); it_a != list.constEnd(); ++it_a) { - MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a); - if (acc.accountType() == eMyMoney::Account::Investment) { - for (it_b = acc.accountList().constBegin(); it_b != acc.accountList().constEnd(); ++it_b) { - if (!list.contains(*it_b)) { - missing.append(*it_b); - } - } - } - } - list += missing; - } - - m_filter.addAccount(list); - } - - // Date tab - if ((int)m_dateRange->dateRange() != 0) { - m_filter.setDateFilter(m_dateRange->fromDate(), m_dateRange->toDate()); - } - - // Amount tab - if ((m_ui->m_amountButton->isChecked() && m_ui->m_amountEdit->isValid())) { - m_filter.setAmountFilter(m_ui->m_amountEdit->value(), m_ui->m_amountEdit->value()); - - } else if ((m_ui->m_amountRangeButton->isChecked() - && (m_ui->m_amountFromEdit->isValid() || m_ui->m_amountToEdit->isValid()))) { - - MyMoneyMoney from(MyMoneyMoney::minValue), to(MyMoneyMoney::maxValue); - if (m_ui->m_amountFromEdit->isValid()) - from = m_ui->m_amountFromEdit->value(); - if (m_ui->m_amountToEdit->isValid()) - to = m_ui->m_amountToEdit->value(); - - m_filter.setAmountFilter(from, to); - } - - // Categories tab - if (!m_ui->m_categoriesView->allItemsSelected()) { - m_filter.addCategory(m_ui->m_categoriesView->selectedItems()); - } - - // Tags tab - if (m_ui->m_emptyTagsButton->isChecked()) { - m_filter.addTag(QString()); - - } else if (!allItemsSelected(m_ui->m_tagsView)) { - scanCheckListItems(m_ui->m_tagsView, addTagToFilter); - } - - // Payees tab - if (m_ui->m_emptyPayeesButton->isChecked()) { - m_filter.addPayee(QString()); - - } else if (!allItemsSelected(m_ui->m_payeesView)) { - scanCheckListItems(m_ui->m_payeesView, addPayeeToFilter); - } - - // Details tab - if (m_ui->m_typeBox->currentIndex() != 0) - m_filter.addType(m_ui->m_typeBox->currentIndex()); - - if (m_ui->m_stateBox->currentIndex() != 0) - m_filter.addState(m_ui->m_stateBox->currentIndex()); - - if (m_ui->m_validityBox->currentIndex() != 0) - m_filter.addValidity(m_ui->m_validityBox->currentIndex()); - - if (m_ui->m_nrButton->isChecked() && !m_ui->m_nrEdit->text().isEmpty()) - m_filter.setNumberFilter(m_ui->m_nrEdit->text(), m_ui->m_nrEdit->text()); - - if (m_ui->m_nrRangeButton->isChecked() - && (!m_ui->m_nrFromEdit->text().isEmpty() || !m_ui->m_nrToEdit->text().isEmpty())) { - m_filter.setNumberFilter(m_ui->m_nrFromEdit->text(), m_ui->m_nrToEdit->text()); - } -} - void KFindTransactionDlg::slotSearch() { + Q_D(KFindTransactionDlg); // perform the search only if the button is enabled - if (!m_ui->buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) + if (!d->ui->buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) return; // setup the filter from the dialog widgets - setupFilter(); + d->setupFilter(); // filter is setup, now fill the register slotRefreshView(); - m_ui->m_register->setFocus(); + d->ui->m_register->setFocus(); } void KFindTransactionDlg::slotRefreshView() { - m_needReload = true; + Q_D(KFindTransactionDlg); + d->m_needReload = true; if (isVisible()) { - loadView(); - m_needReload = false; + d->loadView(); + d->m_needReload = false; } } void KFindTransactionDlg::showEvent(QShowEvent* event) { - if (m_needReload) { - loadView(); - m_needReload = false; + Q_D(KFindTransactionDlg); + if (d->m_needReload) { + d->loadView(); + d->m_needReload = false; } QDialog::showEvent(event); } -void KFindTransactionDlg::loadView() -{ - // setup sort order - m_ui->m_register->setSortOrder(KMyMoneyGlobalSettings::sortSearchView()); - - // clear out old data - m_ui->m_register->clear(); - - // retrieve the list from the engine - MyMoneyFile::instance()->transactionList(m_transactionList, m_filter); - - // create the elements for the register - QList >::const_iterator it; - QMapuniqueMap; - MyMoneyMoney deposit, payment; - - int splitCount = 0; - for (it = m_transactionList.constBegin(); it != m_transactionList.constEnd(); ++it) { - const MyMoneySplit& split = (*it).second; - MyMoneyAccount acc = MyMoneyFile::instance()->account(split.accountId()); - ++splitCount; - uniqueMap[(*it).first.id()]++; - - KMyMoneyRegister::Register::transactionFactory(m_ui->m_register, (*it).first, (*it).second, uniqueMap[(*it).first.id()]); - { // debug stuff - if (split.shares().isNegative()) { - payment += split.shares().abs(); - } else { - deposit += split.shares().abs(); - } - } - } - - // add the group markers - m_ui->m_register->addGroupMarkers(); - - // sort the transactions according to the sort setting - m_ui->m_register->sortItems(); - - // remove trailing and adjacent markers - m_ui->m_register->removeUnwantedGroupMarkers(); - - // turn on the ledger lens for the register - m_ui->m_register->setLedgerLensForced(); - - m_ui->m_register->updateRegister(true); - - m_ui->m_register->setFocusToTop(); - m_ui->m_register->selectItem(m_ui->m_register->focusItem()); - -#ifdef KMM_DEBUG - m_ui->m_foundText->setText(i18np("Found %1 matching transaction (D %2 / P %3 = %4)", - "Found %1 matching transactions (D %2 / P %3 = %4)", splitCount, deposit.formatMoney("", 2), payment.formatMoney("", 2), (deposit - payment).formatMoney("", 2))); -#else - m_ui->m_foundText->setText(i18np("Found %1 matching transaction", "Found %1 matching transactions", splitCount)); -#endif - - m_ui->m_tabWidget->setTabEnabled(m_ui->m_tabWidget->indexOf(m_ui->m_resultPage), true); - m_ui->m_tabWidget->setCurrentIndex(m_ui->m_tabWidget->indexOf(m_ui->m_resultPage)); - - QTimer::singleShot(10, this, SLOT(slotRightSize())); -} - void KFindTransactionDlg::slotRightSize() { - m_ui->m_register->update(); + Q_D(KFindTransactionDlg); + d->ui->m_register->update(); } void KFindTransactionDlg::resizeEvent(QResizeEvent* ev) { + Q_D(KFindTransactionDlg); // Columns // 1 = Date // 2 = Account // 4 = Detail // 5 = C // 6 = Payment // 7 = Deposit // don't forget the resizer QDialog::resizeEvent(ev); - if (!m_ui->m_register->isVisible()) + if (!d->ui->m_register->isVisible()) return; // resize the register - int w = m_ui->m_register->contentsRect().width(); + int w = d->ui->m_register->contentsRect().width(); int m_debitWidth = 80; int m_creditWidth = 80; - m_ui->m_register->adjustColumn(1); - m_ui->m_register->adjustColumn(2); - m_ui->m_register->adjustColumn(5); + d->ui->m_register->adjustColumn(1); + d->ui->m_register->adjustColumn(2); + d->ui->m_register->adjustColumn(5); - m_ui->m_register->setColumnWidth(6, m_debitWidth); - m_ui->m_register->setColumnWidth(7, m_creditWidth); + d->ui->m_register->setColumnWidth(6, m_debitWidth); + d->ui->m_register->setColumnWidth(7, m_creditWidth); - for (int i = 0; i < m_ui->m_register->columnCount(); ++i) { + for (auto i = 0; i < d->ui->m_register->columnCount(); ++i) { switch (i) { case 4: // skip the one, we want to set break; default: - w -= m_ui->m_register->columnWidth(i); + w -= d->ui->m_register->columnWidth(i); break; } } - m_ui->m_register->setColumnWidth(4, w); + d->ui->m_register->setColumnWidth(4, w); } void KFindTransactionDlg::slotSelectTransaction() { - QList list = m_ui->m_register->selectedItems(); + Q_D(KFindTransactionDlg); + auto list = d->ui->m_register->selectedItems(); if (!list.isEmpty()) { KMyMoneyRegister::Transaction* t = dynamic_cast(list[0]); if (t) { emit transactionSelected(t->split().accountId(), t->transaction().id()); hide(); } } } bool KFindTransactionDlg::eventFilter(QObject* o, QEvent* e) { - bool rc = false; + Q_D(KFindTransactionDlg); + auto rc = false; if (o->isWidgetType()) { if (e->type() == QEvent::KeyPress) { const QWidget* w = dynamic_cast(o); QKeyEvent *k = static_cast(e); - if (w == m_ui->m_register) { + if (w == d->ui->m_register) { switch (k->key()) { default: break; case Qt::Key_Return: case Qt::Key_Enter: rc = true; slotSelectTransaction(); break; } } } } return rc; } void KFindTransactionDlg::slotShowHelp() { - QString anchor = m_helpAnchor[m_ui->m_criteriaTab->currentWidget()]; + Q_D(KFindTransactionDlg); + auto anchor = d->m_helpAnchor[d->ui->m_criteriaTab->currentWidget()]; if (anchor.isEmpty()) anchor = QString("details.search"); KHelpClient::invokeHelp(anchor); } void KFindTransactionDlg::slotSortOptions() { QPointer dlg = new KSortOptionDlg(this); dlg->setSortOption(KMyMoneyGlobalSettings::sortSearchView(), QString()); dlg->hideDefaultButton(); if (dlg->exec() == QDialog::Accepted) { QString sortOrder = dlg->sortOption(); if (sortOrder != KMyMoneyGlobalSettings::sortSearchView()) { KMyMoneyGlobalSettings::setSortSearchView(sortOrder); slotRefreshView(); } } delete dlg; } diff --git a/kmymoney/dialogs/kfindtransactiondlg.h b/kmymoney/dialogs/kfindtransactiondlg.h index 61309fd4e..6c16baaa3 100644 --- a/kmymoney/dialogs/kfindtransactiondlg.h +++ b/kmymoney/dialogs/kfindtransactiondlg.h @@ -1,208 +1,129 @@ /*************************************************************************** kfindtransactiondlg.h ------------------- copyright : (C) 2003 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KFINDTRANSACTIONDLG_H #define KFINDTRANSACTIONDLG_H // ---------------------------------------------------------------------------- // QT Includes #include -#include -#include -#include // ---------------------------------------------------------------------------- // KDE Includes -#include - // ---------------------------------------------------------------------------- // Project Includes -#include "mymoneysplit.h" -#include "mymoneytransaction.h" -#include "mymoneytransactionfilter.h" - -class QTreeWidget; class QTreeWidgetItem; -class DateRangeDlg; + +namespace Ui { class KSortOptionDlg; } /** * @author Thomas Baumgart */ class KSortOptionDlg : public QDialog { + Q_OBJECT + Q_DISABLE_COPY(KSortOptionDlg) + public: - KSortOptionDlg(QWidget *parent); + explicit KSortOptionDlg(QWidget *parent = nullptr); ~KSortOptionDlg(); - void init(); + void setSortOption(const QString& option, const QString& def); QString sortOption() const; void hideDefaultButton(); private: - struct Private; - Private* const d; + Ui::KSortOptionDlg *ui; }; -namespace Ui -{ -class KFindTransactionDlgDecl; -} - +class KFindTransactionDlgPrivate; class KFindTransactionDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KFindTransactionDlg) public: /** @param withEquityAccounts set to false to hide equity accounts in account page */ - KFindTransactionDlg(QWidget *parent = 0, bool withEquityAccounts = false); - ~KFindTransactionDlg(); + explicit KFindTransactionDlg(QWidget *parent = nullptr, bool withEquityAccounts = false); + virtual ~KFindTransactionDlg(); - virtual bool eventFilter(QObject *o, QEvent *e); - -protected: - void resizeEvent(QResizeEvent*); - void showEvent(QShowEvent* event); + bool eventFilter(QObject *o, QEvent *e) override; protected slots: virtual void slotReset(); virtual void slotSearch(); /** * This slot opens the detailed help page in khelpcenter. The * anchor for the information is taken from m_helpAnchor. */ virtual void slotShowHelp(); - void slotUpdateSelections(); virtual void slotAmountSelected(); virtual void slotAmountRangeSelected(); virtual void slotSelectAllPayees(); virtual void slotDeselectAllPayees(); virtual void slotSelectAllTags(); virtual void slotDeselectAllTags(); virtual void slotNrSelected(); virtual void slotNrRangeSelected(); void slotRefreshView(); /** * This slot selects the current selected transaction/split and emits * the signal @a transactionSelected(const QString& accountId, const QString& transactionId) */ void slotSelectTransaction(); void slotRightSize(); void slotSortOptions(); signals: void transactionSelected(const QString& accountId, const QString& transactionId); /** * This signal is sent out when a selection has been made. It is * used to control the state of the Search button. * The Search button is only active when a selection has been made * (i.e. notEmpty == true) */ void selectionNotEmpty(bool); protected: - enum opTypeE { - addAccountToFilter = 0, - addCategoryToFilter, - addPayeeToFilter, - addTagToFilter - }; - - void setupCategoriesPage(); - void setupAccountsPage(bool withEquityAccounts=false); - void setupAmountPage(); - void setupPayeesPage(); - void setupTagsPage(); - void setupDetailsPage(); - - void setupFilter(); - - void selectAllItems(QTreeWidget* view, const bool state); - void selectAllSubItems(QTreeWidgetItem* item, const bool state); - void selectItems(QTreeWidget* view, const QStringList& list, const bool state); - void selectSubItems(QTreeWidgetItem* item, const QStringList& list, const bool state); - - /** - * This method loads the m_payeesView with the payees name - * found in the engine. - */ - void loadPayees(); + KFindTransactionDlgPrivate * const d_ptr; + KFindTransactionDlg(KFindTransactionDlgPrivate &dd, QWidget *parent, bool withEquityAccounts); - /** - * This method loads the m_tagsView with the tags name - * found in the engine. - */ - void loadTags(); + void resizeEvent(QResizeEvent*) override; + void showEvent(QShowEvent* event) override; - /** - * This method loads the register with the matching transactions - */ - void loadView(); - - /** - * This method returns information about the selection state - * of the items in the m_accountsView. - * - * @param view pointer to the listview to scan - * - * @retval true if all items in the view are marked - * @retval false if at least one item is not marked - * - * @note If the view contains no items the method returns @p true. - */ - bool allItemsSelected(const QTreeWidget* view) const; - bool allItemsSelected(const QTreeWidgetItem *item) const; - - void scanCheckListItems(const QTreeWidget* view, const opTypeE op); - void scanCheckListItems(const QTreeWidgetItem* item, const opTypeE op); - void addItemToFilter(const opTypeE op, const QString& id); - -protected: - QDate m_startDates[(int)eMyMoney::TransactionFilter::Date::LastDateItem]; - QDate m_endDates[(int)eMyMoney::TransactionFilter::Date::LastDateItem]; - - /** - * This member holds a list of all transactions matching the filter criteria - */ - QList > m_transactionList; - - MyMoneyTransactionFilter m_filter; - - QMap m_helpAnchor; - - bool m_needReload; - - Ui::KFindTransactionDlgDecl* m_ui; - DateRangeDlg *m_dateRange; +private: + Q_DECLARE_PRIVATE(KFindTransactionDlg) }; #endif diff --git a/kmymoney/dialogs/kfindtransactiondlgdecl.ui b/kmymoney/dialogs/kfindtransactiondlg.ui similarity index 99% rename from kmymoney/dialogs/kfindtransactiondlgdecl.ui rename to kmymoney/dialogs/kfindtransactiondlg.ui index 78bc3f4d3..a1176f5e0 100644 --- a/kmymoney/dialogs/kfindtransactiondlgdecl.ui +++ b/kmymoney/dialogs/kfindtransactiondlg.ui @@ -1,960 +1,960 @@ - KFindTransactionDlgDecl - + KFindTransactionDlg + 0 0 771 481 Search transactions true Criteria Define your search criteria false 0 3 0 Text Qt::Vertical QSizePolicy::Expanding 16 83 1 0 300 0 true Contains Does not contain Treat text as regular expression Case sensitive Account 6 11 11 11 11 Date Qt::Horizontal QSizePolicy::Expanding 40 20 Qt::Vertical QSizePolicy::Expanding 20 30 Amount QFrame::NoFrame QFrame::Sunken 0 0 0 0 Search this amount ButtonGroup1 Search amount in the range ButtonGroup1 100 0 false to false 100 0 from false 100 0 Qt::Horizontal QSizePolicy::Expanding 16 16 Qt::Vertical QSizePolicy::Expanding 16 75 Category Tag 6 11 11 11 11 6 0 0 0 0 false Tag Select transactions without tags 6 0 0 0 0 Select all Select none Qt::Vertical QSizePolicy::Expanding 0 42 Payee 6 11 11 11 11 6 0 0 0 0 false Payee Select transactions without payees 6 0 0 0 0 Select all Select none Qt::Vertical QSizePolicy::Expanding 0 42 Details Validity false Type false All states Not reconciled Cleared Reconciled All types Payments Deposits Transfers Any transaction Valid transaction Invalid transaction State false Qt::Horizontal QSizePolicy::Expanding 130 20 QFrame::NoFrame Search this number ButtonGroup2 0 0 Search number in range ButtonGroup2 false to false from false Qt::Horizontal QSizePolicy::Expanding 20 20 Qt::Vertical QSizePolicy::Expanding 16 16 text Qt::AlignTop false 75 true false Qt::Vertical QSizePolicy::Expanding 20 24 Result 0 12 F Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter false QDialogButtonBox::Apply|QDialogButtonBox::Close|QDialogButtonBox::Help|QDialogButtonBox::Reset KLineEdit QLineEdit
klineedit.h
KComboBox QComboBox
kcombobox.h
kMyMoneyLineEdit QWidget
../widgets/kmymoneylineedit.h
kMyMoneyAccountSelector QWidget
../widgets/kmymoneyaccountselector.h
kMyMoneyEdit QWidget
kmymoneyedit.h
1
KMyMoneyRegister::Register QWidget
register.h
m_tabWidget m_criteriaTab m_textEdit m_textNegate m_caseSensitive m_regExp m_amountButton m_amountRangeButton m_tagsView m_emptyTagsButton m_allTagsButton m_clearTagsButton m_payeesView m_emptyPayeesButton m_allPayeesButton m_clearPayeesButton m_typeBox m_stateBox m_validityBox m_nrButton m_nrRangeButton
diff --git a/kmymoney/dialogs/kfindtransactiondlg_p.h b/kmymoney/dialogs/kfindtransactiondlg_p.h new file mode 100644 index 000000000..30e9ef7a8 --- /dev/null +++ b/kmymoney/dialogs/kfindtransactiondlg_p.h @@ -0,0 +1,627 @@ +/*************************************************************************** + kfindtransactiondlg.cpp + ------------------- + copyright : (C) 2003, 2007 by Thomas Baumgart + email : ipwizard@users.sourceforge.net + (C) 2017 by Łukasz Wojniłowicz + ***************************************************************************/ + +/*************************************************************************** + * * + * q 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. * + * * + ***************************************************************************/ + +#ifndef KFINDTRANSACTIONDLG_P_H +#define KFINDTRANSACTIONDLG_P_H + +#include "kfindtransactiondlg.h" + +// ---------------------------------------------------------------------------- +// QT Includes + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- +// KDE Includes + +#include +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- +// Project Includes + +#include "kmymoneyedit.h" +#include "mymoneyfile.h" +#include "mymoneypayee.h" +#include "mymoneytag.h" +#include "kmymoneyglobalsettings.h" +#include "register.h" +#include "transaction.h" +#include "daterangedlg.h" + +#include "ui_kfindtransactiondlg.h" + +class KFindTransactionDlgPrivate +{ + Q_DISABLE_COPY(KFindTransactionDlgPrivate) + Q_DECLARE_PUBLIC(KFindTransactionDlg) + +public: + enum opTypeE { + addAccountToFilter = 0, + addCategoryToFilter, + addPayeeToFilter, + addTagToFilter + }; + + KFindTransactionDlgPrivate(KFindTransactionDlg *qq) : + q_ptr(qq), + ui(new Ui::KFindTransactionDlg) + { + } + + ~KFindTransactionDlgPrivate() + { + delete ui; + } + + void init(bool withEquityAccounts) + { + Q_Q(KFindTransactionDlg); + m_needReload = false; + ui->setupUi(q); + m_dateRange = new DateRangeDlg; + ui->dateRangeLayout->insertWidget(0, m_dateRange); + + ui->ButtonGroup1->setId(ui->m_amountButton, 0); + ui->ButtonGroup1->setId(ui->m_amountRangeButton, 1); + + ui->m_register->installEventFilter(q); + ui->m_tabWidget->setTabEnabled(ui->m_tabWidget->indexOf(ui->m_resultPage), false); + + // 'cause we don't have a separate setupTextPage + q->connect(ui->m_textEdit, &QLineEdit::textChanged, q, &KFindTransactionDlg::slotUpdateSelections); + // if return is pressed trigger a search (slotSearch checks if it's possible to perform the search) + q->connect(ui->m_textEdit, &KLineEdit::returnPressed, q, &KFindTransactionDlg::slotSearch); + // in case the date selection changes, we update the selection + q->connect(m_dateRange, &DateRangeDlg::rangeChanged, q, &KFindTransactionDlg::slotUpdateSelections); + + setupAccountsPage(withEquityAccounts); + setupCategoriesPage(); + setupAmountPage(); + setupPayeesPage(); + setupTagsPage(); + setupDetailsPage(); + + // We don't need to add the default into the list (see ::slotShowHelp() why) + // m_helpAnchor[m_ui->m_textTab] = QLatin1String("details.search"); + m_helpAnchor[ui->m_accountTab] = QLatin1String("details.search.account"); + m_helpAnchor[ui->m_dateTab] = QLatin1String("details.search.date"); + m_helpAnchor[ui->m_amountTab] = QLatin1String("details.search.amount"); + m_helpAnchor[ui->m_categoryTab] = QLatin1String("details.search.category"); + m_helpAnchor[ui->m_payeeTab] = QLatin1String("details.search.payee"); + m_helpAnchor[ui->m_tagTab] = QLatin1String("details.search.tag"); //FIXME-ALEX update Help + m_helpAnchor[ui->m_detailsTab] = QLatin1String("details.search.details"); + + // setup the register + QList cols { + KMyMoneyRegister::DateColumn, + KMyMoneyRegister::AccountColumn, + KMyMoneyRegister::DetailColumn, + KMyMoneyRegister::ReconcileFlagColumn, + KMyMoneyRegister::PaymentColumn, + KMyMoneyRegister::DepositColumn}; + ui->m_register->setupRegister(MyMoneyAccount(), cols); + ui->m_register->setSelectionMode(QTableWidget::SingleSelection); + + q->connect(ui->m_register, &KMyMoneyRegister::Register::editTransaction, q, &KFindTransactionDlg::slotSelectTransaction); + q->connect(ui->m_register->horizontalHeader(), &QWidget::customContextMenuRequested, q, &KFindTransactionDlg::slotSortOptions); + + q->slotUpdateSelections(); + + // setup the connections + q->connect(ui->buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, q, &KFindTransactionDlg::slotSearch); + q->connect(ui->buttonBox->button(QDialogButtonBox::Reset), &QAbstractButton::clicked, q, &KFindTransactionDlg::slotReset); + q->connect(ui->buttonBox->button(QDialogButtonBox::Reset), &QAbstractButton::clicked, ui->m_accountsView, &kMyMoneyAccountSelector::slotSelectAllAccounts); + q->connect(ui->buttonBox->button(QDialogButtonBox::Reset), &QAbstractButton::clicked, ui->m_categoriesView, &kMyMoneyAccountSelector::slotSelectAllAccounts); + q->connect(ui->buttonBox->button(QDialogButtonBox::Close), &QAbstractButton::clicked, q, &QObject::deleteLater); + q->connect(ui->buttonBox->button(QDialogButtonBox::Help), &QAbstractButton::clicked, q, &KFindTransactionDlg::slotShowHelp); + + // only allow searches when a selection has been made + ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); + KGuiItem::assign(ui->buttonBox->button(QDialogButtonBox::Apply), KStandardGuiItem::find()); + ui->buttonBox->button(QDialogButtonBox::Apply)->setToolTip(i18nc("@info:tooltip for find transaction apply button", "Search transactions")); + q->connect(q, &KFindTransactionDlg::selectionNotEmpty, ui->buttonBox->button(QDialogButtonBox::Apply), &QWidget::setEnabled); + + // get signal about engine changes + q->connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, q, &KFindTransactionDlg::slotRefreshView); + + q->slotUpdateSelections(); + + ui->m_textEdit->setFocus(); + } + + /** + * q method returns information about the selection state + * of the items in the m_accountsView. + * + * @param view pointer to the listview to scan + * + * @retval true if all items in the view are marked + * @retval false if at least one item is not marked + * + * @note If the view contains no items the method returns @p true. + */ + bool allItemsSelected(const QTreeWidgetItem *item) const + { + QTreeWidgetItem* it_v; + + for (auto i = 0; i < item->childCount(); ++i) { + it_v = item->child(i); + if (!(it_v->checkState(0) == Qt::Checked && allItemsSelected(it_v))) { + return false; + } + } + return true; + } + + bool allItemsSelected(const QTreeWidget* view) const + { + QTreeWidgetItem* it_v; + + for (int i = 0; i < view->invisibleRootItem()->childCount(); ++i) { + it_v = view->invisibleRootItem()->child(i); + if (it_v->flags() & Qt::ItemIsUserCheckable) { + if (!(it_v->checkState(0) == Qt::Checked && allItemsSelected(it_v))) { + return false; + } else { + if (!allItemsSelected(it_v)) + return false; + } + } + } + return true; + } + + void addItemToFilter(const opTypeE op, const QString& id) + { + switch (op) { + case addAccountToFilter: + m_filter.addAccount(id); + break; + case addCategoryToFilter: + m_filter.addCategory(id); + break; + case addPayeeToFilter: + m_filter.addPayee(id); + break; + case addTagToFilter: + m_filter.addTag(id); + break; + } + } + + void scanCheckListItems(const QTreeWidgetItem* item, const opTypeE op) + { + QTreeWidgetItem* it_v; + + for (auto i = 0; i < item->childCount(); ++i) { + it_v = item->child(i); + QVariant idData = it_v->data(0, Qt::UserRole); + if (it_v->flags() & Qt::ItemIsUserCheckable) { + if (it_v->checkState(0) == Qt::Checked) + addItemToFilter(op, idData.toString()); + } + scanCheckListItems(it_v, op); + } + } + + void scanCheckListItems(const QTreeWidget* view, const opTypeE op) + { + QTreeWidgetItem* it_v; + + for (auto i = 0; i < view->invisibleRootItem()->childCount(); ++i) { + it_v = view->invisibleRootItem()->child(i); + QVariant idData = it_v->data(0, Qt::UserRole); + if (it_v->flags() & Qt::ItemIsUserCheckable) { + if (it_v->checkState(0) == Qt::Checked) { + addItemToFilter(op, idData.toString()); + } + } + scanCheckListItems(it_v, op); + } + } + + void selectAllItems(QTreeWidget* view, const bool state) + { + QTreeWidgetItem* it_v; + + for (int i = 0; i < view->invisibleRootItem()->childCount(); ++i) { + it_v = view->invisibleRootItem()->child(i); + if (it_v->flags() & Qt::ItemIsUserCheckable) { + it_v->setCheckState(0, state ? Qt::Checked : Qt::Unchecked); + } + selectAllSubItems(it_v, state); + } + Q_Q(KFindTransactionDlg); + q->slotUpdateSelections(); + } + + void selectItems(QTreeWidget* view, const QStringList& list, const bool state) + { + QTreeWidgetItem* it_v; + + for (int i = 0; i < view->invisibleRootItem()->childCount(); ++i) { + it_v = view->invisibleRootItem()->child(i); + QVariant idData = it_v->data(0, Qt::UserRole); + if (it_v->flags() & Qt::ItemIsUserCheckable && list.contains(idData.toString())) { + it_v->setCheckState(0, state ? Qt::Checked : Qt::Unchecked); + } + selectSubItems(it_v, list, state); + } + + Q_Q(KFindTransactionDlg); + q->slotUpdateSelections(); + } + + void selectAllSubItems(QTreeWidgetItem* item, const bool state) + { + QTreeWidgetItem* it_v; + + for (int i = 0; i < item->childCount(); ++i) { + it_v = item->child(i); + it_v->setCheckState(0, state ? Qt::Checked : Qt::Unchecked); + selectAllSubItems(it_v, state); + } + } + + void selectSubItems(QTreeWidgetItem* item, const QStringList& list, const bool state) + { + QTreeWidgetItem* it_v; + + for (int i = 0; i < item->childCount(); ++i) { + it_v = item->child(i); + QVariant idData = it_v->data(0, Qt::UserRole); + if (list.contains(idData.toString())) + it_v->setCheckState(0, state ? Qt::Checked : Qt::Unchecked); + selectSubItems(it_v, list, state); + } + } + + /** + * q method loads the register with the matching transactions + */ + void loadView() + { + // setup sort order + ui->m_register->setSortOrder(KMyMoneyGlobalSettings::sortSearchView()); + + // clear out old data + ui->m_register->clear(); + + // retrieve the list from the engine + MyMoneyFile::instance()->transactionList(m_transactionList, m_filter); + + // create the elements for the register + QList >::const_iterator it; + QMapuniqueMap; + MyMoneyMoney deposit, payment; + + int splitCount = 0; + for (it = m_transactionList.constBegin(); it != m_transactionList.constEnd(); ++it) { + const MyMoneySplit& split = (*it).second; + MyMoneyAccount acc = MyMoneyFile::instance()->account(split.accountId()); + ++splitCount; + uniqueMap[(*it).first.id()]++; + + KMyMoneyRegister::Register::transactionFactory(ui->m_register, (*it).first, (*it).second, uniqueMap[(*it).first.id()]); + { // debug stuff + if (split.shares().isNegative()) { + payment += split.shares().abs(); + } else { + deposit += split.shares().abs(); + } + } + } + + // add the group markers + ui->m_register->addGroupMarkers(); + + // sort the transactions according to the sort setting + ui->m_register->sortItems(); + + // remove trailing and adjacent markers + ui->m_register->removeUnwantedGroupMarkers(); + + // turn on the ledger lens for the register + ui->m_register->setLedgerLensForced(); + + ui->m_register->updateRegister(true); + + ui->m_register->setFocusToTop(); + ui->m_register->selectItem(ui->m_register->focusItem()); + + #ifdef KMM_DEBUG + ui->m_foundText->setText(i18np("Found %1 matching transaction (D %2 / P %3 = %4)", + "Found %1 matching transactions (D %2 / P %3 = %4)", splitCount, deposit.formatMoney("", 2), payment.formatMoney("", 2), (deposit - payment).formatMoney("", 2))); + #else + ui->m_foundText->setText(i18np("Found %1 matching transaction", "Found %1 matching transactions", splitCount)); + #endif + + ui->m_tabWidget->setTabEnabled(ui->m_tabWidget->indexOf(ui->m_resultPage), true); + ui->m_tabWidget->setCurrentIndex(ui->m_tabWidget->indexOf(ui->m_resultPage)); + + Q_Q(KFindTransactionDlg); + QTimer::singleShot(10, q, SLOT(slotRightSize())); + } + + /** + * q method loads the m_tagsView with the tags name + * found in the engine. + */ + void loadTags() + { + MyMoneyFile* file = MyMoneyFile::instance(); + QList list; + QList::Iterator it_l; + + list = file->tagList(); + // load view + for (it_l = list.begin(); it_l != list.end(); ++it_l) { + auto item = new QTreeWidgetItem(ui->m_tagsView); + item->setText(0, (*it_l).name()); + item->setData(0, Qt::UserRole, (*it_l).id()); + item->setCheckState(0, Qt::Checked); + } + } + + /** + * q method loads the m_payeesView with the payees name + * found in the engine. + */ + void loadPayees() + { + MyMoneyFile* file = MyMoneyFile::instance(); + QList list; + QList::Iterator it_l; + + list = file->payeeList(); + // load view + for (it_l = list.begin(); it_l != list.end(); ++it_l) { + auto item = new QTreeWidgetItem(ui->m_payeesView); + item->setText(0, (*it_l).name()); + item->setData(0, Qt::UserRole, (*it_l).id()); + item->setCheckState(0, Qt::Checked); + } + } + + void setupFilter() + { + m_filter.clear(); + + // Text tab + if (!ui->m_textEdit->text().isEmpty()) { + QRegExp exp(ui->m_textEdit->text(), ui->m_caseSensitive->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive, !ui->m_regExp->isChecked() ? QRegExp::Wildcard : QRegExp::RegExp); + m_filter.setTextFilter(exp, ui->m_textNegate->currentIndex() != 0); + } + + // Account tab + if (!ui->m_accountsView->allItemsSelected()) { + // retrieve a list of selected accounts + QStringList list; + ui->m_accountsView->selectedItems(list); + + // if we're not in expert mode, we need to make sure + // that all stock accounts for the selected investment + // account are also selected + if (!KMyMoneyGlobalSettings::expertMode()) { + QStringList missing; + QStringList::const_iterator it_a, it_b; + for (it_a = list.constBegin(); it_a != list.constEnd(); ++it_a) { + MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a); + if (acc.accountType() == eMyMoney::Account::Investment) { + for (it_b = acc.accountList().constBegin(); it_b != acc.accountList().constEnd(); ++it_b) { + if (!list.contains(*it_b)) { + missing.append(*it_b); + } + } + } + } + list += missing; + } + + m_filter.addAccount(list); + } + + // Date tab + if ((int)m_dateRange->dateRange() != 0) { + m_filter.setDateFilter(m_dateRange->fromDate(), m_dateRange->toDate()); + } + + // Amount tab + if ((ui->m_amountButton->isChecked() && ui->m_amountEdit->isValid())) { + m_filter.setAmountFilter(ui->m_amountEdit->value(), ui->m_amountEdit->value()); + + } else if ((ui->m_amountRangeButton->isChecked() + && (ui->m_amountFromEdit->isValid() || ui->m_amountToEdit->isValid()))) { + + MyMoneyMoney from(MyMoneyMoney::minValue), to(MyMoneyMoney::maxValue); + if (ui->m_amountFromEdit->isValid()) + from = ui->m_amountFromEdit->value(); + if (ui->m_amountToEdit->isValid()) + to = ui->m_amountToEdit->value(); + + m_filter.setAmountFilter(from, to); + } + + // Categories tab + if (!ui->m_categoriesView->allItemsSelected()) { + m_filter.addCategory(ui->m_categoriesView->selectedItems()); + } + + // Tags tab + if (ui->m_emptyTagsButton->isChecked()) { + m_filter.addTag(QString()); + + } else if (!allItemsSelected(ui->m_tagsView)) { + scanCheckListItems(ui->m_tagsView, addTagToFilter); + } + + // Payees tab + if (ui->m_emptyPayeesButton->isChecked()) { + m_filter.addPayee(QString()); + + } else if (!allItemsSelected(ui->m_payeesView)) { + scanCheckListItems(ui->m_payeesView, addPayeeToFilter); + } + + // Details tab + if (ui->m_typeBox->currentIndex() != 0) + m_filter.addType(ui->m_typeBox->currentIndex()); + + if (ui->m_stateBox->currentIndex() != 0) + m_filter.addState(ui->m_stateBox->currentIndex()); + + if (ui->m_validityBox->currentIndex() != 0) + m_filter.addValidity(ui->m_validityBox->currentIndex()); + + if (ui->m_nrButton->isChecked() && !ui->m_nrEdit->text().isEmpty()) + m_filter.setNumberFilter(ui->m_nrEdit->text(), ui->m_nrEdit->text()); + + if (ui->m_nrRangeButton->isChecked() + && (!ui->m_nrFromEdit->text().isEmpty() || !ui->m_nrToEdit->text().isEmpty())) { + m_filter.setNumberFilter(ui->m_nrFromEdit->text(), ui->m_nrToEdit->text()); + } + } + + void setupDetailsPage() + { + Q_Q(KFindTransactionDlg); + q->connect(ui->m_typeBox, static_cast(&QComboBox::activated), q, &KFindTransactionDlg::slotUpdateSelections); + q->connect(ui->m_stateBox, static_cast(&QComboBox::activated), q, &KFindTransactionDlg::slotUpdateSelections); + q->connect(ui->m_validityBox, static_cast(&QComboBox::activated), q, &KFindTransactionDlg::slotUpdateSelections); + + q->connect(ui->m_nrButton, &QAbstractButton::clicked, q, &KFindTransactionDlg::slotNrSelected); + q->connect(ui->m_nrRangeButton, &QAbstractButton::clicked, q, &KFindTransactionDlg::slotNrRangeSelected); + q->connect(ui->m_nrEdit, &QLineEdit::textChanged, q, &KFindTransactionDlg::slotUpdateSelections); + q->connect(ui->m_nrFromEdit, &QLineEdit::textChanged, q, &KFindTransactionDlg::slotUpdateSelections); + q->connect(ui->m_nrToEdit, &QLineEdit::textChanged, q, &KFindTransactionDlg::slotUpdateSelections); + + ui->m_nrButton->setChecked(true); + q->slotNrSelected(); + } + + void setupTagsPage() + { + Q_Q(KFindTransactionDlg); + ui->m_tagsView->setSelectionMode(QAbstractItemView::SingleSelection); + ui->m_tagsView->header()->hide(); + ui->m_tagsView->setAlternatingRowColors(true); + + loadTags(); + + ui->m_tagsView->sortItems(0, Qt::AscendingOrder); + ui->m_emptyTagsButton->setCheckState(Qt::Unchecked); + + q->connect(ui->m_allTagsButton, &QAbstractButton::clicked, q, &KFindTransactionDlg::slotSelectAllTags); + q->connect(ui->m_clearTagsButton, &QAbstractButton::clicked, q, &KFindTransactionDlg::slotDeselectAllTags); + q->connect(ui->m_emptyTagsButton, &QCheckBox::stateChanged, q, &KFindTransactionDlg::slotUpdateSelections); + q->connect(ui->m_tagsView, &QTreeWidget::itemChanged, q, &KFindTransactionDlg::slotUpdateSelections); + } + + void setupPayeesPage() + { + Q_Q(KFindTransactionDlg); + ui->m_payeesView->setSelectionMode(QAbstractItemView::SingleSelection); + ui->m_payeesView->header()->hide(); + ui->m_payeesView->setAlternatingRowColors(true); + + loadPayees(); + + ui->m_payeesView->sortItems(0, Qt::AscendingOrder); + ui->m_emptyPayeesButton->setCheckState(Qt::Unchecked); + + q->connect(ui->m_allPayeesButton, &QAbstractButton::clicked, q, &KFindTransactionDlg::slotSelectAllPayees); + q->connect(ui->m_clearPayeesButton, &QAbstractButton::clicked, q, &KFindTransactionDlg::slotDeselectAllPayees); + q->connect(ui->m_emptyPayeesButton, &QCheckBox::stateChanged, q, &KFindTransactionDlg::slotUpdateSelections); + q->connect(ui->m_payeesView, &QTreeWidget::itemChanged, q, &KFindTransactionDlg::slotUpdateSelections); + } + + void setupAmountPage() + { + Q_Q(KFindTransactionDlg); + q->connect(ui->m_amountButton, &QAbstractButton::clicked, q, &KFindTransactionDlg::slotAmountSelected); + q->connect(ui->m_amountRangeButton, &QAbstractButton::clicked, q, &KFindTransactionDlg::slotAmountRangeSelected); + + q->connect(ui->m_amountEdit, &kMyMoneyEdit::textChanged, q, &KFindTransactionDlg::slotUpdateSelections); + q->connect(ui->m_amountFromEdit, &kMyMoneyEdit::textChanged, q, &KFindTransactionDlg::slotUpdateSelections); + q->connect(ui->m_amountToEdit, &kMyMoneyEdit::textChanged, q, &KFindTransactionDlg::slotUpdateSelections); + + ui->m_amountButton->setChecked(true); + q->slotAmountSelected(); + } + + void setupCategoriesPage() + { + Q_Q(KFindTransactionDlg); + ui->m_categoriesView->setSelectionMode(QTreeWidget::MultiSelection); + AccountSet categorySet; + categorySet.addAccountGroup(eMyMoney::Account::Income); + categorySet.addAccountGroup(eMyMoney::Account::Expense); + categorySet.load(ui->m_categoriesView); + q->connect(ui->m_categoriesView, &kMyMoneyAccountSelector::stateChanged, q, &KFindTransactionDlg::slotUpdateSelections); + } + + void setupAccountsPage(bool withEquityAccounts) + { + Q_Q(KFindTransactionDlg); + ui->m_accountsView->setSelectionMode(QTreeWidget::MultiSelection); + AccountSet accountSet; + accountSet.addAccountGroup(eMyMoney::Account::Asset); + accountSet.addAccountGroup(eMyMoney::Account::Liability); + + if (withEquityAccounts) + accountSet.addAccountGroup(eMyMoney::Account::Equity); + + //set the accountset to show closed account if the settings say so + accountSet.setHideClosedAccounts(KMyMoneyGlobalSettings::hideClosedAccounts()); + accountSet.load(ui->m_accountsView); + q->connect(ui->m_accountsView, &kMyMoneyAccountSelector::stateChanged, q, &KFindTransactionDlg::slotUpdateSelections); + } + + KFindTransactionDlg *q_ptr; + Ui::KFindTransactionDlg *ui; + QDate m_startDates[(int)eMyMoney::TransactionFilter::Date::LastDateItem]; + QDate m_endDates[(int)eMyMoney::TransactionFilter::Date::LastDateItem]; + + /** + * q member holds a list of all transactions matching the filter criteria + */ + QList > m_transactionList; + + MyMoneyTransactionFilter m_filter; + + QMap m_helpAnchor; + + bool m_needReload; + DateRangeDlg *m_dateRange; + +}; + +#endif diff --git a/kmymoney/dialogs/kgeneratesqldlg.cpp b/kmymoney/dialogs/kgeneratesqldlg.cpp index 5e507d51e..8e3a20e06 100644 --- a/kmymoney/dialogs/kgeneratesqldlg.cpp +++ b/kmymoney/dialogs/kgeneratesqldlg.cpp @@ -1,301 +1,340 @@ /*************************************************************************** kgeneratesqldlg.cpp ------------------- copyright : (C) 2009 by Tony Bloomfield + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kgeneratesqldlg.h" // ---------------------------------------------------------------------------- -// System includes +// Std Includes + +#include -#include +// ---------------------------------------------------------------------------- +// System includes // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include #include #include -#include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kgeneratesqldlg.h" + #include "mymoneyfile.h" -#include "storage/mymoneystoragesql.h" #include "storage/mymoneyseqaccessmgr.h" #include "kguiutils.h" #include "misc/platformtools.h" +#include "mymoneydbdriver.h" +#include "mymoneydbdef.h" -KGenerateSqlDlg::KGenerateSqlDlg(QWidget *) +class KGenerateSqlDlgPrivate { - m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel|QDialogButtonBox::Help); - m_createTablesButton = m_buttonBox->addButton(i18n("Create Tables"), QDialogButtonBox::ButtonRole::AcceptRole); - m_saveSqlButton = m_buttonBox->addButton(i18n("Save SQL"), QDialogButtonBox::ButtonRole::ActionRole); - Q_ASSERT(m_createTablesButton); - Q_ASSERT(m_saveSqlButton); - - QPushButton *okButton = m_buttonBox->button(QDialogButtonBox::Ok); - okButton->setDefault(true); - okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - - m_widget = new KGenerateSqlDlgDecl(); - QVBoxLayout *mainLayout = new QVBoxLayout; - setLayout(mainLayout); - mainLayout->addWidget(m_widget); - - QWidget *mainWidget = new QWidget(this); - setLayout(mainLayout); - mainLayout->addWidget(mainWidget); - mainLayout->addWidget(m_buttonBox); - initializeForm(); -} + Q_DISABLE_COPY(KGenerateSqlDlgPrivate) + Q_DECLARE_PUBLIC(KGenerateSqlDlg) + +public: + KGenerateSqlDlgPrivate(KGenerateSqlDlg *qq) : + q_ptr(qq), + ui(new Ui::KGenerateSqlDlg) + { + } -KGenerateSqlDlg::~KGenerateSqlDlg() + ~KGenerateSqlDlgPrivate() + { + delete ui; + } + + void init() + { + Q_Q(KGenerateSqlDlg); + ui->setupUi(q); + m_createTablesButton = ui->buttonBox->addButton(i18n("Create Tables"), QDialogButtonBox::ButtonRole::AcceptRole); + m_saveSqlButton = ui->buttonBox->addButton(i18n("Save SQL"), QDialogButtonBox::ButtonRole::ActionRole); + Q_ASSERT(m_createTablesButton); + Q_ASSERT(m_saveSqlButton); + + q->connect(ui->buttonBox, &QDialogButtonBox::accepted, q, &QDialog::accept); + q->connect(ui->buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject); + initializeForm(); + } + + void initializeForm() + { + Q_Q(KGenerateSqlDlg); + m_requiredFields = nullptr; + // at this point, we don't know which fields are required, so disable everything but the list + m_saveSqlButton->setEnabled(false); + m_createTablesButton->setEnabled(false); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + + ui->urlSqlite->clear(); + ui->textDbName->clear(); + ui->textHostName->clear(); + ui->textPassword->clear(); + ui->textUserName->clear(); + ui->textSQL->clear(); + ui->urlSqlite->setEnabled(false); + ui->textDbName->setEnabled(false); + ui->textHostName->setEnabled(false); + ui->textPassword->setEnabled(false); + ui->textUserName->setEnabled(false); + ui->textSQL->setEnabled(false); + + q->connect(ui->buttonBox->button(QDialogButtonBox::Help), &QPushButton::clicked, q, &KGenerateSqlDlg::slotHelp); + } + + QString selectedDriver() + { + auto drivers = ui->listDrivers->selectedItems(); + if (drivers.count() != 1) { + return QString(); + } + + return drivers[0]->text().section(' ', 0, 0); + } + + KGenerateSqlDlg *q_ptr; + Ui::KGenerateSqlDlg *ui; + QPushButton *m_createTablesButton; + QPushButton *m_saveSqlButton; + + QList m_supportedDrivers; + //MyMoneyDbDrivers m_map; + std::unique_ptr m_requiredFields; + bool m_sqliteSelected; + QExplicitlySharedDataPointer m_dbDriver; + QString m_dbName; + MyMoneySeqAccessMgr* m_storage; + bool m_mustDetachStorage; +}; + + +KGenerateSqlDlg::KGenerateSqlDlg(QWidget *parent) : + QDialog(parent), + d_ptr(new KGenerateSqlDlgPrivate(this)) { - // Stub required to delete m_requiredFields + Q_D(KGenerateSqlDlg); + d->init(); } -void KGenerateSqlDlg::initializeForm() +KGenerateSqlDlg::~KGenerateSqlDlg() { - m_requiredFields = nullptr; - // at this point, we don't know which fields are required, so disable everything but the list - m_saveSqlButton->setEnabled(false); - m_createTablesButton->setEnabled(false); - QPushButton* okButton = m_buttonBox->button(QDialogButtonBox::Ok); - Q_ASSERT(okButton); - okButton->setEnabled(false); - - m_widget->urlSqlite->clear(); - m_widget->textDbName->clear(); - m_widget->textHostName->clear(); - m_widget->textPassword->clear(); - m_widget->textUserName->clear(); - m_widget->textSQL->clear(); - m_widget->urlSqlite->setEnabled(false); - m_widget->textDbName->setEnabled(false); - m_widget->textHostName->setEnabled(false); - m_widget->textPassword->setEnabled(false); - m_widget->textUserName->setEnabled(false); - m_widget->textSQL->setEnabled(false); - - connect(m_buttonBox->button(QDialogButtonBox::Help), &QPushButton::clicked, this, &KGenerateSqlDlg::slotHelp); + Q_D(KGenerateSqlDlg); + delete d; } int KGenerateSqlDlg::exec() { + Q_D(KGenerateSqlDlg); // list drivers supported by KMM - QMap map = MyMoneyDbDriver::driverMap(); + auto map = MyMoneyDbDriver::driverMap(); // list drivers installed on system - QStringList list = QSqlDatabase::drivers(); + auto list = QSqlDatabase::drivers(); // join the two QStringList::Iterator it = list.begin(); while (it != list.end()) { QString dname = *it; if (map.keys().contains(dname)) { // only keep if driver is supported dname = dname + " - " + map[dname]; - m_supportedDrivers.append(dname); + d->m_supportedDrivers.append(dname); } ++it; } - if (m_supportedDrivers.count() == 0) { + if (d->m_supportedDrivers.count() == 0) { // why does KMessageBox not have a standard dialog with Help button? if ((KMessageBox::questionYesNo(this, i18n("In order to use a database, you need to install some additional software. Click Help for more information"), i18n("No Qt SQL Drivers"), KStandardGuiItem::help(), KStandardGuiItem::cancel())) == KMessageBox::Yes) { // Yes stands in for help here KHelpClient::invokeHelp("details.database.usage"); } return (1); } - m_widget->listDrivers->clear(); - m_widget->listDrivers->addItems(m_supportedDrivers); - connect(m_widget->listDrivers, SIGNAL(itemSelectionChanged()), - this, SLOT(slotdriverSelected())); + d->ui->listDrivers->clear(); + d->ui->listDrivers->addItems(d->m_supportedDrivers); + connect(d->ui->listDrivers, &QListWidget::itemSelectionChanged, + this, &KGenerateSqlDlg::slotdriverSelected); return (QDialog::exec()); } void KGenerateSqlDlg::slotcreateTables() { - if (m_sqliteSelected) { - m_dbName = m_widget->urlSqlite->text(); + Q_D(KGenerateSqlDlg); + if (d->m_sqliteSelected) { + d->m_dbName = d->ui->urlSqlite->text(); } else { - m_dbName = m_widget->textDbName->text(); + d->m_dbName = d->ui->textDbName->text(); } // check that the database has been pre-created { // all queries etc. must be in a block - see 'remove database' API doc - Q_ASSERT(!selectedDriver().isEmpty()); + Q_ASSERT(!d->selectedDriver().isEmpty()); - QSqlDatabase dbase = QSqlDatabase::addDatabase(selectedDriver(), "creation"); - dbase.setHostName(m_widget->textHostName->text()); - dbase.setDatabaseName(m_dbName); - dbase.setUserName(m_widget->textUserName->text()); - dbase.setPassword(m_widget->textPassword->text()); + QSqlDatabase dbase = QSqlDatabase::addDatabase(d->selectedDriver(), "creation"); + dbase.setHostName(d->ui->textHostName->text()); + dbase.setDatabaseName(d->m_dbName); + dbase.setUserName(d->ui->textUserName->text()); + dbase.setPassword(d->ui->textPassword->text()); if (!dbase.open()) { KMessageBox::error(this, i18n("Unable to open database.\n" "You must use an SQL CREATE DATABASE statement before creating the tables.\n") ); return; } QSqlQuery q(dbase); QString message(i18n("Tables successfully created")); - QStringList commands = m_widget->textSQL->toPlainText().split('\n'); + QStringList commands = d->ui->textSQL->toPlainText().split('\n'); QStringList::ConstIterator cit; for (cit = commands.constBegin(); cit != commands.constEnd(); ++cit) { if (!(*cit).isEmpty()) { //qDebug() << "exec" << *cit; q.prepare(*cit); if (!q.exec()) { QSqlError e = q.lastError(); message = i18n("Creation failed executing statement" "\nExecuted: %1" "\nError No %2: %3", q.executedQuery(), e.number(), e.text()); break; } } } KMessageBox::information(this, message); } QSqlDatabase::removeDatabase("creation"); - QPushButton* okButton = m_buttonBox->button(QDialogButtonBox::Ok); + auto okButton = d->ui->buttonBox->button(QDialogButtonBox::Ok); Q_ASSERT(okButton); okButton->setEnabled(true); } void KGenerateSqlDlg::slotsaveSQL() { - QString fileName = QFileDialog::getSaveFileName( - this, - i18n("Select output file"), - QString(), - QString()); + Q_D(KGenerateSqlDlg); + auto fileName = QFileDialog::getSaveFileName( + this, + i18n("Select output file"), + QString(), + QString()); if (fileName.isEmpty()) return; QFile out(fileName); if (!out.open(QIODevice::WriteOnly)) return; QTextStream s(&out); MyMoneyDbDef db; - s << m_widget->textSQL->toPlainText(); + s << d->ui->textSQL->toPlainText(); out.close(); - QPushButton* okButton = m_buttonBox->button(QDialogButtonBox::Ok); + auto okButton = d->ui->buttonBox->button(QDialogButtonBox::Ok); Q_ASSERT(okButton); okButton->setEnabled(true); } -QString KGenerateSqlDlg::selectedDriver() -{ - QList drivers = m_widget->listDrivers->selectedItems(); - if (drivers.count() != 1) { - return QString(); - } - - return drivers[0]->text().section(' ', 0, 0); -} - void KGenerateSqlDlg::slotdriverSelected() { - const QString driverName = selectedDriver(); + Q_D(KGenerateSqlDlg); + const auto driverName = d->selectedDriver(); if (driverName.isEmpty()) { - initializeForm(); + d->initializeForm(); return; } - m_dbDriver = MyMoneyDbDriver::create(driverName); - if (!m_dbDriver->isTested()) { + d->m_dbDriver = MyMoneyDbDriver::create(driverName); + if (!d->m_dbDriver->isTested()) { int rc = KMessageBox::warningContinueCancel(0, i18n("Database type %1 has not been fully tested in a KMyMoney environment.\n" "Please make sure you have adequate backups of your data.\n" "Please report any problems to the developer mailing list at " "kmymoney-devel@kde.org", driverName), ""); if (rc == KMessageBox::Cancel) { - m_widget->listDrivers->clearSelection(); - initializeForm(); + d->ui->listDrivers->clearSelection(); + d->initializeForm(); return; } } - m_requiredFields.reset(new kMandatoryFieldGroup(this)); + d->m_requiredFields.reset(new kMandatoryFieldGroup(this)); // currently, only sqlite need an external file - if (m_dbDriver->requiresExternalFile()) { - m_sqliteSelected = true; - m_widget->urlSqlite->setMode(KFile::Mode::File); - m_widget->urlSqlite->setEnabled(true); - m_requiredFields->add(m_widget->urlSqlite); - - m_widget->textDbName->setEnabled(false); - m_widget->textHostName->setEnabled(false); - m_widget->textUserName->setEnabled(false); + if (d->m_dbDriver->requiresExternalFile()) { + d->m_sqliteSelected = true; + d->ui->urlSqlite->setMode(KFile::Mode::File); + d->ui->urlSqlite->setEnabled(true); + d->m_requiredFields->add(d->ui->urlSqlite); + + d->ui->textDbName->setEnabled(false); + d->ui->textHostName->setEnabled(false); + d->ui->textUserName->setEnabled(false); } else { // not sqlite3 - m_sqliteSelected = false; - m_widget->urlSqlite->setEnabled(false); - m_widget->textDbName->setEnabled(true); - m_widget->textHostName->setEnabled(true); - m_widget->textUserName->setEnabled(true); - m_requiredFields->add(m_widget->textDbName); - m_requiredFields->add(m_widget->textHostName); - m_requiredFields->add(m_widget->textUserName); - m_widget->textDbName->setText("KMyMoney"); - m_widget->textHostName->setText("localhost"); - m_widget->textUserName->setText(""); - m_widget->textUserName->setText(platformTools::osUsername()); - m_widget->textPassword->setText(""); + d->m_sqliteSelected = false; + d->ui->urlSqlite->setEnabled(false); + d->ui->textDbName->setEnabled(true); + d->ui->textHostName->setEnabled(true); + d->ui->textUserName->setEnabled(true); + d->m_requiredFields->add(d->ui->textDbName); + d->m_requiredFields->add(d->ui->textHostName); + d->m_requiredFields->add(d->ui->textUserName); + d->ui->textDbName->setText("KMyMoney"); + d->ui->textHostName->setText("localhost"); + d->ui->textUserName->setText(""); + d->ui->textUserName->setText(platformTools::osUsername()); + d->ui->textPassword->setText(""); } - m_widget->textPassword->setEnabled(m_dbDriver->isPasswordSupported()); - m_requiredFields->setOkButton(m_createTablesButton); - m_widget->textSQL->setEnabled(true); + d->ui->textPassword->setEnabled(d->m_dbDriver->isPasswordSupported()); + d->m_requiredFields->setOkButton(d->m_createTablesButton); + d->ui->textSQL->setEnabled(true); // check if we have a storage; if not, create a skeleton one // we need a storage for MyMoneyDbDef to generate standard accounts - m_storage = new MyMoneySeqAccessMgr; - m_mustDetachStorage = true; + d->m_storage = new MyMoneySeqAccessMgr; + d->m_mustDetachStorage = true; try { - MyMoneyFile::instance()->attachStorage(m_storage); + MyMoneyFile::instance()->attachStorage(d->m_storage); } catch (const MyMoneyException &) { - m_mustDetachStorage = false; // there is already a storage attached + d->m_mustDetachStorage = false; // there is already a storage attached } MyMoneyDbDef db; - m_widget->textSQL->setText - (db.generateSQL(m_dbDriver)); - if (m_mustDetachStorage) { + d->ui->textSQL->setText + (db.generateSQL(d->m_dbDriver)); + if (d->m_mustDetachStorage) { MyMoneyFile::instance()->detachStorage(); } - delete m_storage; + delete d->m_storage; - m_saveSqlButton->setEnabled(true); - connect(m_saveSqlButton, &QPushButton::clicked, this, &KGenerateSqlDlg::slotsaveSQL); - connect(m_createTablesButton, &QPushButton::clicked, this, &KGenerateSqlDlg::slotcreateTables); + d->m_saveSqlButton->setEnabled(true); + connect(d->m_saveSqlButton, &QPushButton::clicked, this, &KGenerateSqlDlg::slotsaveSQL); + connect(d->m_createTablesButton, &QPushButton::clicked, this, &KGenerateSqlDlg::slotcreateTables); } void KGenerateSqlDlg::slotHelp() { KHelpClient::invokeHelp("details.database.generatesql"); } diff --git a/kmymoney/dialogs/kgeneratesqldlg.h b/kmymoney/dialogs/kgeneratesqldlg.h index 0272dce55..827b2b69a 100644 --- a/kmymoney/dialogs/kgeneratesqldlg.h +++ b/kmymoney/dialogs/kgeneratesqldlg.h @@ -1,84 +1,58 @@ /*************************************************************************** kgeneratesql.h ------------------- copyright : (C) 2005 by Tony Bloomfield + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KGENERATESQLDLG_H #define KGENERATESQLDLG_H -// ---------------------------------------------------------------------------- -// Std Includes - -#include - // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_kgeneratesqldlgdecl.h" - -class QDialogButtonBox; -class MyMoneyDbDriver; -class MyMoneySeqAccessMgr; -class kMandatoryFieldGroup; -class KGenerateSqlDlgDecl : public QWidget, public Ui::KGenerateSqlDlgDecl -{ -public: - KGenerateSqlDlgDecl() { - setupUi(this); - } -}; - +class KGenerateSqlDlgPrivate; class KGenerateSqlDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KGenerateSqlDlg) + public: - explicit KGenerateSqlDlg(QWidget *parent = 0); + explicit KGenerateSqlDlg(QWidget *parent = nullptr); ~KGenerateSqlDlg(); /** * execute the generation */ - int exec(); + int exec() override; + public slots: void slotHelp(); void slotdriverSelected(); void slotcreateTables(); void slotsaveSQL(); -private: - void initializeForm(); - QString selectedDriver(); - KGenerateSqlDlgDecl* m_widget; - QDialogButtonBox* m_buttonBox; - QPushButton* m_createTablesButton; - QPushButton* m_saveSqlButton; +private: + KGenerateSqlDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KGenerateSqlDlg) - QList m_supportedDrivers; - //MyMoneyDbDrivers m_map; - std::unique_ptr m_requiredFields; - bool m_sqliteSelected; - QExplicitlySharedDataPointer m_dbDriver; - QString m_dbName; - MyMoneySeqAccessMgr* m_storage; - bool m_mustDetachStorage; }; #endif diff --git a/kmymoney/dialogs/kgeneratesqldlgdecl.ui b/kmymoney/dialogs/kgeneratesqldlg.ui similarity index 91% rename from kmymoney/dialogs/kgeneratesqldlgdecl.ui rename to kmymoney/dialogs/kgeneratesqldlg.ui index 3561bd29d..fad7ebc5c 100644 --- a/kmymoney/dialogs/kgeneratesqldlgdecl.ui +++ b/kmymoney/dialogs/kgeneratesqldlg.ui @@ -1,171 +1,176 @@ - KGenerateSqlDlgDecl - + KGenerateSqlDlg + 0 0 800 - 501 + 528 0 0 0 0 518 679 KMyMoney - Generate SQL Database Type 0 0 Database Details Database File (SQLite only) Database Name (Others) Host Name Username Password QLineEdit::Password SQL for creation 0 1 + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok + + + false + + + - KUrlRequester - QFrame -
kurlrequester.h
-
- - QListWidget - QListWidget -
klistwidget.h
+ KTextEdit + QTextEdit +
ktextedit.h
KLineEdit QLineEdit
klineedit.h
- KTextEdit - QTextEdit -
ktextedit.h
+ KUrlRequester + QWidget +
kurlrequester.h
diff --git a/kmymoney/dialogs/kgncimportoptionsdlg.cpp b/kmymoney/dialogs/kgncimportoptionsdlg.cpp index 8dbb3a5dd..5cbba46d7 100644 --- a/kmymoney/dialogs/kgncimportoptionsdlg.cpp +++ b/kmymoney/dialogs/kgncimportoptionsdlg.cpp @@ -1,122 +1,190 @@ /*************************************************************************** kgncimportoptions.cpp ------------------- copyright : (C) 2005 by Tony Bloomfield + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kgncimportoptionsdlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include -#include -#include // ---------------------------------------------------------------------------- // Project Includes -// dialog constructor -KGncImportOptionsDlg::KGncImportOptionsDlg(QWidget *) +#include "ui_kgncimportoptionsdlg.h" + +class KGncImportOptionsDlgPrivate +{ + Q_DISABLE_COPY(KGncImportOptionsDlgPrivate) + Q_DECLARE_PUBLIC(KGncImportOptionsDlg) + +public: + KGncImportOptionsDlgPrivate(KGncImportOptionsDlg *qq) : + q_ptr(qq), + ui(new Ui::KGncImportOptionsDlg), + m_localeCodec(nullptr) + { + } + + ~KGncImportOptionsDlgPrivate() + { + delete ui; + } + + void init() + { + Q_Q(KGncImportOptionsDlg); + ui->setupUi(q); + + ui->buttonInvestGroup->setId(ui->radioInvest1, 0); // one invest acct per stock + ui->buttonInvestGroup->setId(ui->radioInvest2, 1); // one invest acct for all stocks + ui->buttonInvestGroup->setId(ui->radioInvest3, 2); // prompt for each stock + + ui->buttonGroup5->setExclusive(false); + ui->checkFinanceQuote->setChecked(true); + + ui->buttonGroup2->setExclusive(false); + ui->checkSchedules->setChecked(false); + + buildCodecList(); // build list of codecs and insert into combo box + + ui->buttonGroup4->setExclusive(false); + ui->checkDecode->setChecked(false); + ui->comboDecode->setEnabled(false); + + ui->buttonGroup18->setExclusive(false); + ui->checkTxNotes->setChecked(false); + + ui->buttonGroup3->setExclusive(false); + ui->checkDebugGeneral->setChecked(false); + ui->checkDebugXML->setChecked(false); + ui->checkAnonymize->setChecked(false); + + q->connect(ui->checkDecode, &QAbstractButton::toggled, q, &KGncImportOptionsDlg::slotDecodeOptionChanged); + q->connect(ui->buttonBox, &QDialogButtonBox::helpRequested, q, &KGncImportOptionsDlg::slotHelp); + } + + void buildCodecList() + { + m_localeCodec = QTextCodec::codecForLocale(); + auto codecList = QTextCodec::availableCodecs(); + QList::ConstIterator itc; + for (itc = codecList.constBegin(); itc != codecList.constEnd(); ++itc) { + if (*itc == m_localeCodec) + ui->comboDecode->insertItem(0, QString(*itc)); + else + ui->comboDecode->insertItem(9999, QString(*itc)); + } + } + + KGncImportOptionsDlg *q_ptr; + Ui::KGncImportOptionsDlg *ui; + QTextCodec *m_localeCodec; +}; + +KGncImportOptionsDlg::KGncImportOptionsDlg(QWidget *parent) : + QDialog(parent), + d_ptr(new KGncImportOptionsDlgPrivate(this)) { - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Help); - QWidget *mainWidget = new QWidget(this); - QVBoxLayout *mainLayout = new QVBoxLayout; - setLayout(mainLayout); - mainLayout->addWidget(mainWidget); - QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); - okButton->setDefault(true); - okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - m_widget = new KGncImportOptionsDlgDecl(); - mainLayout->addWidget(m_widget); - - m_widget->buttonInvestGroup->setId(m_widget->radioInvest1, 0); // one invest acct per stock - m_widget->buttonInvestGroup->setId(m_widget->radioInvest2, 1); // one invest acct for all stocks - m_widget->buttonInvestGroup->setId(m_widget->radioInvest3, 2); // prompt for each stock - - m_widget->buttonGroup5->setExclusive(false); - m_widget->checkFinanceQuote->setChecked(true); - - m_widget->buttonGroup2->setExclusive(false); - m_widget->checkSchedules->setChecked(false); - - buildCodecList(); // build list of codecs and insert into combo box - - m_widget->buttonGroup4->setExclusive(false); - m_widget->checkDecode->setChecked(false); - m_widget->comboDecode->setEnabled(false); - - m_widget->buttonGroup18->setExclusive(false); - m_widget->checkTxNotes->setChecked(false); - - m_widget->buttonGroup3->setExclusive(false); - m_widget->checkDebugGeneral->setChecked(false); - m_widget->checkDebugXML->setChecked(false); - m_widget->checkAnonymize->setChecked(false); - - connect(m_widget->checkDecode, SIGNAL(toggled(bool)), this, SLOT(slotDecodeOptionChanged(bool))); - connect(this, SIGNAL(helpClicked()), this, SLOT(slotHelp())); - - mainLayout->addWidget(buttonBox); + Q_D(KGncImportOptionsDlg); + d->init(); } -KGncImportOptionsDlg::~KGncImportOptionsDlg() {} +KGncImportOptionsDlg::~KGncImportOptionsDlg() +{ + Q_D(KGncImportOptionsDlg); + delete d; +} // enable the combo box for selection if required void KGncImportOptionsDlg::slotDecodeOptionChanged(bool isOn) { + Q_D(KGncImportOptionsDlg); if (isOn) { - m_widget->comboDecode->setEnabled(true); - m_widget->comboDecode->setCurrentItem(0); + d->ui->comboDecode->setEnabled(true); + d->ui->comboDecode->setCurrentItem(0); } else { - m_widget->comboDecode->setEnabled(false); + d->ui->comboDecode->setEnabled(false); } } -void KGncImportOptionsDlg::buildCodecList() + +int KGncImportOptionsDlg::investmentOption() const { - m_localeCodec = QTextCodec::codecForLocale(); - QList codecList = QTextCodec::availableCodecs(); - QList::ConstIterator itc; - for (itc = codecList.constBegin(); itc != codecList.constEnd(); ++itc) { - if (*itc == m_localeCodec) - m_widget->comboDecode->insertItem(0, QString(*itc)); - else - m_widget->comboDecode->insertItem(9999, QString(*itc)); - } -} + Q_D(const KGncImportOptionsDlg); + return (d->ui->buttonInvestGroup->checkedId()); +}; + +bool KGncImportOptionsDlg::quoteOption() const +{ + Q_D(const KGncImportOptionsDlg); + return (d->ui->checkFinanceQuote->isChecked()); +}; + +bool KGncImportOptionsDlg::scheduleOption() const +{ + Q_D(const KGncImportOptionsDlg); + return (d->ui->checkSchedules->isChecked()); +}; // return selected codec or 0 QTextCodec* KGncImportOptionsDlg::decodeOption() { - if (!m_widget->checkDecode->isChecked()) { - return (0); + Q_D(const KGncImportOptionsDlg); + if (!d->ui->checkDecode->isChecked()) { + return nullptr; } else { - return (QTextCodec::codecForName(m_widget->comboDecode->currentText().toUtf8())); + return (QTextCodec::codecForName(d->ui->comboDecode->currentText().toUtf8())); } } +bool KGncImportOptionsDlg::txNotesOption() const +{ + Q_D(const KGncImportOptionsDlg); + return (d->ui->checkTxNotes->isChecked()); +} + +bool KGncImportOptionsDlg::generalDebugOption() const +{ + Q_D(const KGncImportOptionsDlg); + return (d->ui->checkDebugGeneral->isChecked()); +} + +bool KGncImportOptionsDlg::xmlDebugOption() const +{ + Q_D(const KGncImportOptionsDlg); + return (d->ui->checkDebugXML->isChecked()); +} + +bool KGncImportOptionsDlg::anonymizeOption() const +{ + Q_D(const KGncImportOptionsDlg); + return (d->ui->checkAnonymize->isChecked()); +} + void KGncImportOptionsDlg::slotHelp() { KHelpClient::invokeHelp("details.impexp.gncoptions"); } diff --git a/kmymoney/dialogs/kgncimportoptionsdlg.h b/kmymoney/dialogs/kgncimportoptionsdlg.h index c8b91e7cb..6b5b7e50a 100644 --- a/kmymoney/dialogs/kgncimportoptionsdlg.h +++ b/kmymoney/dialogs/kgncimportoptionsdlg.h @@ -1,84 +1,62 @@ /*************************************************************************** kgncimportoptions.h ------------------- copyright : (C) 2005 by Tony Bloomfield + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KGNCIMPORTOPTIONSDLG_H #define KGNCIMPORTOPTIONSDLG_H // ---------------------------------------------------------------------------- // QT Includes -#include -#include #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_kgncimportoptionsdlgdecl.h" class QTextCodec; -class KGncImportOptionsDlgDecl : public QWidget, public Ui::KGncImportOptionsDlgDecl -{ -public: - KGncImportOptionsDlgDecl() { - setupUi(this); - } -}; +class KGncImportOptionsDlgPrivate; class KGncImportOptionsDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KGncImportOptionsDlg) + public: - KGncImportOptionsDlg(QWidget *parent = 0); + explicit KGncImportOptionsDlg(QWidget *parent = nullptr); ~KGncImportOptionsDlg(); - int investmentOption() const { - return (m_widget->buttonInvestGroup->checkedId()); - }; - bool quoteOption() const { - return (m_widget->checkFinanceQuote->isChecked()); - }; - bool scheduleOption() const { - return (m_widget->checkSchedules->isChecked()); - }; + int investmentOption() const; + bool quoteOption() const; + bool scheduleOption() const; QTextCodec* decodeOption(); - bool txNotesOption() const { - return (m_widget->checkTxNotes->isChecked()); - }; - bool generalDebugOption() const { - return (m_widget->checkDebugGeneral->isChecked()); - }; - bool xmlDebugOption() const { - return (m_widget->checkDebugXML->isChecked()); - }; - bool anonymizeOption() const { - return (m_widget->checkAnonymize->isChecked()); - }; + bool txNotesOption() const; + bool generalDebugOption() const; + bool xmlDebugOption() const; + bool anonymizeOption() const; public slots: void slotDecodeOptionChanged(bool); void slotHelp(); private: - void buildCodecList(); - - QTextCodec* m_localeCodec; - KGncImportOptionsDlgDecl* m_widget; + KGncImportOptionsDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KGncImportOptionsDlg) }; #endif diff --git a/kmymoney/dialogs/kgncimportoptionsdlgdecl.ui b/kmymoney/dialogs/kgncimportoptionsdlg.ui similarity index 76% rename from kmymoney/dialogs/kgncimportoptionsdlgdecl.ui rename to kmymoney/dialogs/kgncimportoptionsdlg.ui index 1af03cff0..e34773b9f 100644 --- a/kmymoney/dialogs/kgncimportoptionsdlgdecl.ui +++ b/kmymoney/dialogs/kgncimportoptionsdlg.ui @@ -1,265 +1,314 @@ - KGncImportOptionsDlgDecl - + KGncImportOptionsDlg + 0 0 526 679 526 679 GnuCash Import Options Use 'Help' for more information on these options Qt::AlignCenter false Investment Handling - One investment account for each stock + O&ne investment account for each stock true - buttonInvestGroup + buttonInvestGroup - One investment account for all stocks + One in&vestment account for all stocks - buttonInvestGroup + buttonInvestGroup - Prompt for an investment account for each stock + P&rompt for an investment account for each stock - buttonInvestGroup + buttonInvestGroup Online price quotes Use Finance::Quote for share price quotes - buttonGroup5 + buttonGroup5 Scheduled Transactions Drop suspect scheduled transactions - buttonGroup2 + buttonGroup2 Decoding option 0 - + + 0 + + + 0 + + + 0 + + 0 Decode using - buttonGroup4 + buttonGroup4 Qt::Horizontal QSizePolicy::Expanding 140 20 Transaction Notes option Use transaction notes on non-split transactions - buttonGroup18 + buttonGroup18 QFrame::HLine QFrame::Sunken Debug Options General debug data - buttonGroup3 + buttonGroup3 Display XML data - buttonGroup3 + buttonGroup3 Anonymize data - buttonGroup3 + buttonGroup3 + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok + + + Qt::Vertical 20 25 KComboBox QComboBox
kcombobox.h
- + + + buttonBox + accepted() + KGncImportOptionsDlg + accept() + + + 262 + 599 + + + 262 + 339 + + + + + buttonBox + rejected() + KGncImportOptionsDlg + reject() + + + 262 + 599 + + + 262 + 339 + + + + + + + - - -
diff --git a/kmymoney/dialogs/kgncpricesourcedlg.cpp b/kmymoney/dialogs/kgncpricesourcedlg.cpp index 6cce610ae..fa7de2a8c 100644 --- a/kmymoney/dialogs/kgncpricesourcedlg.cpp +++ b/kmymoney/dialogs/kgncpricesourcedlg.cpp @@ -1,153 +1,143 @@ /*************************************************************************** kgncpricesourcedlg.cpp ------------------- copyright : (C) 2005 by Tony Bloomfield + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kgncpricesourcedlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include -#include -#include // ---------------------------------------------------------------------------- // KDE Includes #include #include // ---------------------------------------------------------------------------- // Project Includes #include "webpricequote.h" -#include "ui_kgncpricesourcedlgdecl.h" +#include "ui_kgncpricesourcedlg.h" - -class KGncPriceSourceDlgDecl : public QWidget, public Ui::KGncPriceSourceDlgDecl +class KGncPriceSourceDlgPrivate { + Q_DISABLE_COPY(KGncPriceSourceDlgPrivate) + public: - KGncPriceSourceDlgDecl() { - setupUi(this); + KGncPriceSourceDlgPrivate() : + ui(new Ui::KGncPriceSourceDlg), + currentButton(0) + { } -}; + ~KGncPriceSourceDlgPrivate() + { + delete ui; + } -struct KGncPriceSourceDlg::Private { - Private() : currentButton(0), widget(0) {} + Ui::KGncPriceSourceDlg *ui; int currentButton; - KGncPriceSourceDlgDecl* widget; }; -KGncPriceSourceDlg::KGncPriceSourceDlg(QWidget *parent) : QDialog(parent), d(new Private) -{ -} -KGncPriceSourceDlg::KGncPriceSourceDlg(const QString &stockName, const QString& gncSource, QWidget * parent) : QDialog(parent), d(new Private) +KGncPriceSourceDlg::KGncPriceSourceDlg(const QString &stockName, const QString& gncSource, QWidget * parent) : + QDialog(parent), + d_ptr(new KGncPriceSourceDlgPrivate) { - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Help); - QWidget *mainWidget = new QWidget(this); - QVBoxLayout *mainLayout = new QVBoxLayout; - setLayout(mainLayout); - mainLayout->addWidget(mainWidget); - QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); - okButton->setDefault(true); - okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - d->widget = new KGncPriceSourceDlgDecl(); - mainLayout->addWidget(d->widget); + Q_D(KGncPriceSourceDlg); + d->ui->setupUi(this); // signals and slots connections - connect(d->widget->buttonsSource, SIGNAL(buttonClicked(int)), this, SLOT(buttonPressed(int))); - connect(this, SIGNAL(helpClicked()), this, SLOT(slotHelp())); + connect(d->ui->buttonsSource, static_cast(&QButtonGroup::buttonClicked), this, &KGncPriceSourceDlg::buttonPressed); + connect(d->ui->buttonBox, &QDialogButtonBox::helpRequested, this, &KGncPriceSourceDlg::slotHelp); // initialize data fields - d->widget->textStockName->setText(i18n("Investment: %1", stockName)); - d->widget->textGncSource->setText(i18n("Quote source: %1", gncSource)); - d->widget->listKnownSource->clear(); - d->widget->listKnownSource->insertItems(0, WebPriceQuote::quoteSources()); - d->widget->lineUserSource->setText(gncSource); - d->widget->checkAlwaysUse->setChecked(true); - d->widget->buttonsSource->setId(d->widget->buttonNoSource, 0); - d->widget->buttonsSource->setId(d->widget->buttonSelectSource, 1); - d->widget->buttonsSource->setId(d->widget->buttonUserSource, 2); - d->widget->buttonsSource->button(0)->setChecked(true); - mainLayout->addWidget(buttonBox); + d->ui->textStockName->setText(i18n("Investment: %1", stockName)); + d->ui->textGncSource->setText(i18n("Quote source: %1", gncSource)); + d->ui->listKnownSource->clear(); + d->ui->listKnownSource->insertItems(0, WebPriceQuote::quoteSources()); + d->ui->lineUserSource->setText(gncSource); + d->ui->checkAlwaysUse->setChecked(true); + d->ui->buttonsSource->setId(d->ui->buttonNoSource, 0); + d->ui->buttonsSource->setId(d->ui->buttonSelectSource, 1); + d->ui->buttonsSource->setId(d->ui->buttonUserSource, 2); + d->ui->buttonsSource->button(0)->setChecked(true); buttonPressed(0); - return; } KGncPriceSourceDlg::~KGncPriceSourceDlg() { + Q_D(KGncPriceSourceDlg); delete d; } enum ButtonIds {NOSOURCE = 0, KMMSOURCE, USERSOURCE}; void KGncPriceSourceDlg::buttonPressed(int buttonId) { + Q_D(KGncPriceSourceDlg); d->currentButton = buttonId; switch (d->currentButton) { case NOSOURCE: - d->widget->listKnownSource->clearSelection(); - d->widget->listKnownSource->setEnabled(false); - d->widget->lineUserSource->deselect(); - d->widget->lineUserSource->setEnabled(false); + d->ui->listKnownSource->clearSelection(); + d->ui->listKnownSource->setEnabled(false); + d->ui->lineUserSource->deselect(); + d->ui->lineUserSource->setEnabled(false); break; case KMMSOURCE: - d->widget->lineUserSource->deselect(); - d->widget->lineUserSource->setEnabled(false); - d->widget->listKnownSource->setEnabled(true); - d->widget->listKnownSource->setFocus(); - d->widget->listKnownSource->setCurrentRow(0); + d->ui->lineUserSource->deselect(); + d->ui->lineUserSource->setEnabled(false); + d->ui->listKnownSource->setEnabled(true); + d->ui->listKnownSource->setFocus(); + d->ui->listKnownSource->setCurrentRow(0); break; case USERSOURCE: - d->widget->listKnownSource->clearSelection(); - d->widget->listKnownSource->setEnabled(false); - d->widget->lineUserSource->setEnabled(true); - d->widget->lineUserSource->selectAll(); - d->widget->lineUserSource->setFocus(); + d->ui->listKnownSource->clearSelection(); + d->ui->listKnownSource->setEnabled(false); + d->ui->lineUserSource->setEnabled(true); + d->ui->lineUserSource->selectAll(); + d->ui->lineUserSource->setFocus(); break; } } QString KGncPriceSourceDlg::selectedSource() const { - QString s; + Q_D(const KGncPriceSourceDlg); switch (d->currentButton) { - case NOSOURCE: - s = ""; - break; case KMMSOURCE: - s = d->widget->listKnownSource->currentItem()->text(); - break; + return d->ui->listKnownSource->currentItem()->text(); case USERSOURCE: - s = d->widget->lineUserSource->text(); - break; + return d->ui->lineUserSource->text(); + case NOSOURCE: + default: + return QString(); } - return (s); } bool KGncPriceSourceDlg::alwaysUse() const { - return d->widget->checkAlwaysUse->isChecked(); + Q_D(const KGncPriceSourceDlg); + return d->ui->checkAlwaysUse->isChecked(); } void KGncPriceSourceDlg::slotHelp() { KHelpClient::invokeHelp("details.impexp.gncquotes"); } diff --git a/kmymoney/dialogs/kgncpricesourcedlg.h b/kmymoney/dialogs/kgncpricesourcedlg.h index 2111ff767..943f9c7e1 100644 --- a/kmymoney/dialogs/kgncpricesourcedlg.h +++ b/kmymoney/dialogs/kgncpricesourcedlg.h @@ -1,53 +1,54 @@ /*************************************************************************** kgncpricesourcedlg.h ------------------- copyright : (C) 2005 by Tony Bloomfield + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KGNCPRICESOURCEDLG_H #define KGNCPRICESOURCEDLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes +class KGncPriceSourceDlgPrivate; class KGncPriceSourceDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KGncPriceSourceDlg) + public: - KGncPriceSourceDlg(QWidget *parent = 0); - KGncPriceSourceDlg(const QString &stockName, const QString &gncSource , QWidget * parent = 0); + explicit KGncPriceSourceDlg(const QString &stockName, const QString &gncSource , QWidget * parent = nullptr); ~KGncPriceSourceDlg(); QString selectedSource() const; bool alwaysUse() const; public slots: void buttonPressed(int); void slotHelp(); private: - /// \internal d-pointer class. - struct Private; - /// \internal d-pointer instance. - Private* const d; + KGncPriceSourceDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KGncPriceSourceDlg) }; #endif diff --git a/kmymoney/dialogs/kgncpricesourcedlgdecl.ui b/kmymoney/dialogs/kgncpricesourcedlg.ui similarity index 66% rename from kmymoney/dialogs/kgncpricesourcedlgdecl.ui rename to kmymoney/dialogs/kgncpricesourcedlg.ui index 4c45ee265..961d1c8c4 100644 --- a/kmymoney/dialogs/kgncpricesourcedlgdecl.ui +++ b/kmymoney/dialogs/kgncpricesourcedlg.ui @@ -1,126 +1,161 @@ - KGncPriceSourceDlgDecl - + KGncPriceSourceDlg + 0 0 619 480 619 480 Online Quotes - Select price source false false This price source is not known to KMyMoney. Please select an option below. false - Do not perform online quotes for this investment + Do &not perform online quotes for this investment - buttonsSource + buttonsSource - Select a known KMyMoney source from the list below + Select a &known KMyMoney source from the list below - buttonsSource + buttonsSource - Use the following name for the price source. + Use the fo&llowing name for the price source. (Click Help for further information.) - buttonsSource + buttonsSource Always use this selection for this price source. + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok + + + - - QListWidget - QListWidget -
klistwidget.h
-
KLineEdit QLineEdit
klineedit.h
- + + + buttonBox + accepted() + KGncPriceSourceDlg + accept() + + + 309 + 456 + + + 309 + 239 + + + + + buttonBox + rejected() + KGncPriceSourceDlg + reject() + + + 309 + 456 + + + 309 + 239 + + + +
diff --git a/kmymoney/dialogs/kgpgkeyselectiondlg.cpp b/kmymoney/dialogs/kgpgkeyselectiondlg.cpp index 38a4d7612..ca15228e1 100644 --- a/kmymoney/dialogs/kgpgkeyselectiondlg.cpp +++ b/kmymoney/dialogs/kgpgkeyselectiondlg.cpp @@ -1,171 +1,210 @@ /*************************************************************************** kgpgkeyselectiondlg.cpp ------------------- copyright : (C) 2008 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kgpgkeyselectiondlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include // ---------------------------------------------------------------------------- // Project Includes #include #include #include +class KGpgKeySelectionDlgPrivate +{ + Q_DISABLE_COPY(KGpgKeySelectionDlgPrivate) + +public: + KGpgKeySelectionDlgPrivate() + { + } + + ~KGpgKeySelectionDlgPrivate() + { + } + + KEditListWidget* m_listWidget; + KLed* m_keyLed; + bool m_needCheckList; + bool m_listOk; + int m_checkCount; +}; + + KGpgKeySelectionDlg::KGpgKeySelectionDlg(QWidget *parent) : QDialog(parent), - m_needCheckList(true), - m_listOk(false), - m_checkCount(0) + d_ptr(new KGpgKeySelectionDlgPrivate) { + Q_D(KGpgKeySelectionDlg); + d->m_needCheckList = true; + d->m_listOk = false; + d->m_checkCount = 0; // TODO: check port to kf5 setWindowTitle(i18n("Select additional keys")); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QWidget *mainWidget = new QWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(mainWidget); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); setModal(true); QWidget* page = new QWidget(this); mainLayout->addWidget(page); mainLayout->addWidget(buttonBox); QGroupBox *listBox = new QGroupBox(i18n("User identification"), page); QVBoxLayout *verticalLayout = new QVBoxLayout(listBox); verticalLayout->setSpacing(6); verticalLayout->setContentsMargins(0, 0, 0, 0); - m_listWidget = new KEditListWidget(listBox); - m_listWidget->connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - m_listWidget->connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - m_listWidget->setWhatsThis(i18n("Enter the id of the key you want to use for data encryption. This can either be an e-mail address or the hexadecimal key id. In case of the key id, do not forget the leading 0x.")); - verticalLayout->addWidget(m_listWidget); + d->m_listWidget = new KEditListWidget(listBox); + d->m_listWidget->connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + d->m_listWidget->connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + d->m_listWidget->setWhatsThis(i18n("Enter the id of the key you want to use for data encryption. This can either be an e-mail address or the hexadecimal key id. In case of the key id, do not forget the leading 0x.")); + verticalLayout->addWidget(d->m_listWidget); // add a LED for the availability of all keys QHBoxLayout* ledBox = new QHBoxLayout(); ledBox->setContentsMargins(0, 0, 0, 0); ledBox->setSpacing(6); ledBox->setObjectName("ledBoxLayout"); - m_keyLed = new KLed(page); - mainLayout->addWidget(m_keyLed); - m_keyLed->setShape(KLed::Circular); - m_keyLed->setLook(KLed::Sunken); + d->m_keyLed = new KLed(page); + mainLayout->addWidget(d->m_keyLed); + d->m_keyLed->setShape(KLed::Circular); + d->m_keyLed->setLook(KLed::Sunken); - ledBox->addWidget(m_keyLed); + ledBox->addWidget(d->m_keyLed); ledBox->addWidget(new QLabel(i18n("Keys for all of the above user ids found"), page)); ledBox->addItem(new QSpacerItem(50, 20, QSizePolicy::Expanding, QSizePolicy::Minimum)); verticalLayout->addLayout(ledBox); - connect(m_listWidget, SIGNAL(changed()), this, SLOT(slotIdChanged())); - connect(m_listWidget, SIGNAL(added(QString)), this, SLOT(slotKeyListChanged())); - connect(m_listWidget, SIGNAL(removed(QString)), this, SLOT(slotKeyListChanged())); + connect(d->m_listWidget, &KEditListWidget::changed, this, &KGpgKeySelectionDlg::slotIdChanged); + connect(d->m_listWidget, &KEditListWidget::added, this, &KGpgKeySelectionDlg::slotKeyListChanged); + connect(d->m_listWidget, &KEditListWidget::removed, this, &KGpgKeySelectionDlg::slotKeyListChanged); +} + +KGpgKeySelectionDlg::~KGpgKeySelectionDlg() +{ + Q_D(KGpgKeySelectionDlg); + delete d; } void KGpgKeySelectionDlg::setKeys(const QStringList& list) { - m_listWidget->clear(); - m_listWidget->insertStringList(list); + Q_D(KGpgKeySelectionDlg); + d->m_listWidget->clear(); + d->m_listWidget->insertStringList(list); slotKeyListChanged(); } +QStringList KGpgKeySelectionDlg::keys() const +{ + Q_D(const KGpgKeySelectionDlg); + return d->m_listWidget->items(); +} + #if 0 void KGpgKeySelectionDlg::slotShowHelp() { QString anchor = m_helpAnchor[m_criteriaTab->currentPage()]; if (anchor.isEmpty()) anchor = QString("details.search"); KHelpClient::invokeHelp(anchor); } #endif void KGpgKeySelectionDlg::slotKeyListChanged() { - m_needCheckList = true; + Q_D(KGpgKeySelectionDlg); + d->m_needCheckList = true; slotIdChanged(); } void KGpgKeySelectionDlg::slotIdChanged() { + Q_D(KGpgKeySelectionDlg); // this looks a bit awkward. Here's why: KGPGFile::keyAvailable() starts // an external task and processes UI events while it waits for the external // process to finish. Thus, the first time we get here, the external process // is started and the user may press a second key which calls this routine // again. // // The second invocation is counted, but the check is not started until the // first one finishes. Once the external process finishes, we check if we // were called in the meantime and restart the check. - if (++m_checkCount == 1) { + if (++d->m_checkCount == 1) { while (1) { // first we check the current edit field if filled bool keysOk = true; - if (!m_listWidget->currentText().isEmpty()) { - keysOk = KGPGFile::keyAvailable(m_listWidget->currentText()); + if (!d->m_listWidget->currentText().isEmpty()) { + keysOk = KGPGFile::keyAvailable(d->m_listWidget->currentText()); } // if it is available, then scan the current list if we need to if (keysOk) { - if (m_needCheckList) { - QStringList keys = m_listWidget->items(); + if (d->m_needCheckList) { + QStringList keys = d->m_listWidget->items(); QStringList::const_iterator it_s; for (it_s = keys.constBegin(); keysOk && it_s != keys.constEnd(); ++it_s) { if (!KGPGFile::keyAvailable(*it_s)) keysOk = false; } - m_listOk = keysOk; - m_needCheckList = false; + d->m_listOk = keysOk; + d->m_needCheckList = false; } else { - keysOk = m_listOk; + keysOk = d->m_listOk; } } // did we receive some more requests to check? - if (m_checkCount > 1) { - m_checkCount = 1; + if (d->m_checkCount > 1) { + d->m_checkCount = 1; continue; } - m_keyLed->setState(static_cast(keysOk && (m_listWidget->items().count() != 0) ? KLed::On : KLed::Off)); + d->m_keyLed->setState(static_cast(keysOk && (d->m_listWidget->items().count() != 0) ? KLed::On : KLed::Off)); // TODO: port to kf5 // okButton->setEnabled((m_listWidget->items().count() == 0) || (m_keyLed->state() == KLed::On)); break; } - --m_checkCount; + --d->m_checkCount; } } diff --git a/kmymoney/dialogs/kgpgkeyselectiondlg.h b/kmymoney/dialogs/kgpgkeyselectiondlg.h index 03783fec8..7a0ddc113 100644 --- a/kmymoney/dialogs/kgpgkeyselectiondlg.h +++ b/kmymoney/dialogs/kgpgkeyselectiondlg.h @@ -1,70 +1,65 @@ /*************************************************************************** kgpgkeyselectiondlg.h ------------------- copyright : (C) 2008 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KGPGKEYSELECTIONDLG_H #define KGPGKEYSELECTIONDLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes -#include - -class KLed; - // ---------------------------------------------------------------------------- // Project Includes /** * @author Thomas Baumgart */ +class KGpgKeySelectionDlgPrivate; class KGpgKeySelectionDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KGpgKeySelectionDlg) + public: - explicit KGpgKeySelectionDlg(QWidget* parent = 0); - virtual ~KGpgKeySelectionDlg() {} + explicit KGpgKeySelectionDlg(QWidget* parent = nullptr); + ~KGpgKeySelectionDlg(); /** * preset the key list with the given key ids in @a list */ void setKeys(const QStringList& list); /** * Returns the list of keys currently listed in the KEditListWidget */ - const QStringList keys() const { - return m_listWidget->items(); - } + QStringList keys() const; protected slots: void slotIdChanged(); void slotKeyListChanged(); private: - KEditListWidget* m_listWidget; - KLed* m_keyLed; - bool m_needCheckList; - bool m_listOk; - int m_checkCount; + KGpgKeySelectionDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KGpgKeySelectionDlg) }; #endif diff --git a/kmymoney/dialogs/kimportverifydlgdecl.ui b/kmymoney/dialogs/kimportverifydlg.ui similarity index 98% rename from kmymoney/dialogs/kimportverifydlgdecl.ui rename to kmymoney/dialogs/kimportverifydlg.ui index 275f4c427..2387a5215 100644 --- a/kmymoney/dialogs/kimportverifydlgdecl.ui +++ b/kmymoney/dialogs/kimportverifydlg.ui @@ -1,123 +1,123 @@ - KImportVerifyDlgDecl - + KImportVerifyDlg + 0 0 746 525 Verify Import true 11 6 5 5 0 5 QFrame::HLine QFrame::Sunken 0 6 Help 506 0 QSizePolicy::Expanding Qt::Horizontal OK Cancel KGlobalLedgerView QWidget
../views/kgloballedgerview.h
-1 -1 0 5 5 image0
789c6dd7594f23471007f0f7fd14d6d6db2aaaf58c3db647511eb831b7317794879ac30760cc61c010e5bba7dcf5af5688167664fdb66bbaababbb67cccf1f8dab93c3c68f9fdf5e16b298968d7222cf8d1fd5eb6cf6f1e75f7ffcfded7b9a3656ff9aad46fafdb76fdf078b46d9389a3fd42bf04841699e964933b830b79a7019dd0b96955b895b5a703bcd572e08eea576ff6570ae0eedd477b792103f854b8b2fc6d1163f77237e646e37113f89b6f8307e3bf1785a8b0eedbc696eb7ad9db7e01ee6476ee4ffe0c6fd158c7c69182cde4eec6e87fea50dfbf8176e6ba7d07f96669999cfa325ccaf862bcc97a36dbccf60f178cee11cde706761f16917ae30fe6b7488a7851bf14d7327417f676eb4f756eea41e2f57e6d83e83919f6cba117f04235fd9765b3b0fa36dfc398cf973edc67a6fb951ffe768ab6765ee26b8dff213ef5f4630e2b9e7463ea7ee8ee5ff60ee2618af8eb6fe3238437eb91bf1299cdbfacad3cadd5617f5a11738c7fe4adcb8ffd68d7aeec15e8fc3683b9f62ee2518ef33dafa3f75e3bc957086f86eb4d56f3db8e8e6dd56f01a5cc1bbe65e629673d8ebd18d0efdc9058cf9f2c08df9e630ce037db8719ec37c7a9a7fb708f10267b65e7cef46fb3e9ca3fd23dad6ef0cf67abe99f304f95ec3a8871cbb71be52d8d777e8b6fee412f6f958be3adf5ea817b561afe7d86ded7c67ce13c46fc37ede2766c17a17059cd9f38e466e8c3f8eb6fd700f0b9ef7095c37cd3d37de178f2be76dcf876fa343bd790267f012f67a77cc319f69b4ed872e2ca8e732daeabfe3c6fa9cc235f21f9b8bd4f2a5cd687bfedbfd659ee7ede017b842becf6eb44fa3cbd0df8559b0ffe808ceb0ff37e01afba3652e52cc87a26dbe276ecca7097790ff73b4cdef0616ac4fdf6df1c2d1d67ee8c6f80318eb4bd1180ff529513f0ecf7b694b62f5a002ceccb2662e523c2fb7605f9f0fd8fbbf75e3bc2dcd3e9ebcb9f17ce8c05e8f83685bcf701e44eb2db65e4fd1b65eebe62245be53b8c6f3ffdd8dfd3933fbf884761f5f0edcd88f951bf118bf44bde926dae24fe01ae7af76e3f9169e2f45bb143c0f5fdcf6fea23b18f773eac6f3e63ddac6db75e37df5e8c6fbae65aebcde6d37beaf84f528aa52f03c9dc3359ea79939c627d136deab1befaf75b883ef23e76e3ccfaea36d7dc2f795322b05ebfb0ad738af7db7ad371f99fd7e59b8b13f276e9cdf1318f5e54337e6d78cb67cf761ec170efba1acaa1afd9db92d3f3a36d729ea77efc6f33cbccf2beddfe6478fe6d85e45dbfd851bf1577007f5d877e3bc86f5a9ea3a2d6cffdfc1debe116df5db73a39e37b0e777191dda257c7fa83b6e8a2eaae00eeceb13d6b7d69f325b79b058fd32b170c1a55ebffaac2ccae2b9e6118f79c253bd6ef9ee3fd7587fef79c60f7acf3cc617fcc84ffcac6d8ffcc20b7ee5377ee7257ff027aff1bac66ff0269716cf5b1ab7cd3bbcabb17ddee37d3ee0433ee2633ee1019ff290cff89c2ff89229c48b66f1ac3d5df135df7093134eb9c56dcef4b3c35dee71ce393111dbfa8c784a4205955451cd1d1ad1982634a55bbad3f80eddd38c1ef882e66cf52ab5ff2b8d7ea4277aa6175ad06bb866f446efb4d4df0ffad4fed762ffb7b44e1b9cd2266dd142c75e5ddb3cd0bb3e347a477bd9d5f83ee245e3f7689f0ee830f67d44c77412ee186946033aa5e197fecfe85c7bf7be2fe892aee89a6ea84989f6bfa434f4eff9df52c509b5d0779b32ea684d13ea528f728d1e882ebfce37f6cf077422b4ea5b440ad14af1a15452ab473aee52c65ff39789b64fe955f44eb9937b5d858c5b32d377c0c32a7fee7ecd5fe61aff284ff22c2fb290577993775db1443fb53ef2219f5ff2bf93356d5b970dd9d41eb77820dbb223bbab155ed55ffab2f725ffb1eccb81aed6931cca116ab490633909d10339fd5ffdef795d869ae7923bc27226e772415d5986b51d683663b9d4fcfbb1ff190fe54aaec35aeaa577ee20f24673e94b531249a585fc2b69ebfe3ed7dae91f75ba964b5c03e9d344ba1add93bce0826c3f87f3b2a9fb6f18aeba10ba2f563f25eb1b563771a5d17531e2513c5fba538b3111cd690dd73c7ef6a95f4c8aa99de12fe77da4951de9ffffea730be7fd9fdfbffd0b690edc6c
diff --git a/kmymoney/dialogs/kloadtemplatedlg.cpp b/kmymoney/dialogs/kloadtemplatedlg.cpp index 556bb9381..4f82674d5 100644 --- a/kmymoney/dialogs/kloadtemplatedlg.cpp +++ b/kmymoney/dialogs/kloadtemplatedlg.cpp @@ -1,46 +1,56 @@ /*************************************************************************** kloadtemplatedlg.cpp ------------------- copyright : (C) 2008 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kloadtemplatedlg.h" // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "kaccounttemplateselector.h" +#include "ui_kloadtemplatedlg.h" + #include "mymoneytemplate.h" +#include "kaccounttemplateselector.h" KLoadTemplateDlg::KLoadTemplateDlg(QWidget* parent) : - KLoadTemplateDlgDecl(parent) + QDialog(parent), + ui(new Ui::KLoadTemplateDlg) +{ + ui->setupUi(this); + connect(ui->buttonBox, &QDialogButtonBox::helpRequested, this, &KLoadTemplateDlg::slotHelp); +} + +KLoadTemplateDlg::~KLoadTemplateDlg() { - connect(buttonBox, SIGNAL(helpRequested()), this, SLOT(slotHelp())); + delete ui; } QList KLoadTemplateDlg::templates() const { - return m_templateSelector->selectedTemplates(); + return ui->m_templateSelector->selectedTemplates(); } void KLoadTemplateDlg::slotHelp() { } diff --git a/kmymoney/dialogs/kloadtemplatedlg.h b/kmymoney/dialogs/kloadtemplatedlg.h index ed93130a7..cf43c6553 100644 --- a/kmymoney/dialogs/kloadtemplatedlg.h +++ b/kmymoney/dialogs/kloadtemplatedlg.h @@ -1,55 +1,57 @@ /*************************************************************************** kloadtemplatedlg.h ------------------- copyright : (C) 2008 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KLOADTEMPLATEDLG_H #define KLOADTEMPLATEDLG_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_kloadtemplatedlgdecl.h" -#include +template class QList; + +namespace Ui { class KLoadTemplateDlg; } class MyMoneyTemplate; -class KLoadTemplateDlgDecl : public QDialog, public Ui::KLoadTemplateDlgDecl -{ -public: - KLoadTemplateDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; /// This dialog lets the user load more account templates -class KLoadTemplateDlg : public KLoadTemplateDlgDecl +class KLoadTemplateDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KLoadTemplateDlg) public: - KLoadTemplateDlg(QWidget *parent = 0); + explicit KLoadTemplateDlg(QWidget *parent = nullptr); + ~KLoadTemplateDlg(); QList templates() const; private slots: void slotHelp(); + +private: + Ui::KLoadTemplateDlg *ui; }; #endif diff --git a/kmymoney/dialogs/kloadtemplatedlgdecl.ui b/kmymoney/dialogs/kloadtemplatedlg.ui similarity index 89% rename from kmymoney/dialogs/kloadtemplatedlgdecl.ui rename to kmymoney/dialogs/kloadtemplatedlg.ui index 232506d26..1531a9164 100644 --- a/kmymoney/dialogs/kloadtemplatedlgdecl.ui +++ b/kmymoney/dialogs/kloadtemplatedlg.ui @@ -1,75 +1,75 @@ - KLoadTemplateDlgDecl - + KLoadTemplateDlg + 0 0 636 509 MyDialog true QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok KAccountTemplateSelector QWidget
kaccounttemplateselector.h
buttonBox accepted() - KLoadTemplateDlgDecl + KLoadTemplateDlg accept() 500 481 152 503 buttonBox rejected() - KLoadTemplateDlgDecl + KLoadTemplateDlg reject() 576 480 543 505
diff --git a/kmymoney/dialogs/kmergetransactionsdlg.cpp b/kmymoney/dialogs/kmergetransactionsdlg.cpp index 6e8c4fafd..2eecc28b1 100644 --- a/kmymoney/dialogs/kmergetransactionsdlg.cpp +++ b/kmymoney/dialogs/kmergetransactionsdlg.cpp @@ -1,55 +1,62 @@ /*************************************************************************** kmergetransactionsdlg.cpp ------------------- begin : Sun Aug 20 2006 copyright : (C) 2006 by Ace Jones email : + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kmergetransactionsdlg.h" +#include "kselecttransactionsdlg_p.h" // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kselecttransactionsdlg.h" + #include "register.h" -#include "mymoneyaccount.h" KMergeTransactionsDlg::KMergeTransactionsDlg(const MyMoneyAccount& account, QWidget* parent) : KSelectTransactionsDlg(account, parent) { - // setup descriptive texts setWindowTitle(i18n("Merge Transactions")); - m_description->setText(i18n("Are you sure you wish to merge these transactions?")); + d_ptr->ui->m_description->setText(i18n("Are you sure you wish to merge these transactions?")); // no selection possible - m_register->setSelectionMode(QTableWidget::NoSelection); + d_ptr->ui->m_register->setSelectionMode(QTableWidget::NoSelection); // override default and enable ok button right away - buttonOk->setEnabled(true); + d_ptr->ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); +} + +bool KMergeTransactionsDlg::eventFilter(QObject* , QEvent*) +{ + return false; } void KMergeTransactionsDlg::slotHelp() { KHelpClient::invokeHelp("details.ledgers.match"); } diff --git a/kmymoney/dialogs/kmergetransactionsdlg.h b/kmymoney/dialogs/kmergetransactionsdlg.h index 19399f1ef..434d1b44f 100644 --- a/kmymoney/dialogs/kmergetransactionsdlg.h +++ b/kmymoney/dialogs/kmergetransactionsdlg.h @@ -1,47 +1,46 @@ /*************************************************************************** kmergetransactionsdlg.h ------------------- begin : Sun Aug 20 2006 copyright : (C) 2006 by Ace Jones email : + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KMERGETRANSACTIONSDLG_H #define KMERGETRANSACTIONSDLG_H // ---------------------------------------------------------------------------- // QT Includes // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes #include "kselecttransactionsdlg.h" class MyMoneyAccount; class KMergeTransactionsDlg: public KSelectTransactionsDlg { Q_OBJECT public: - explicit KMergeTransactionsDlg(const MyMoneyAccount& account, QWidget* parent = 0); + explicit KMergeTransactionsDlg(const MyMoneyAccount& account, QWidget* parent = nullptr); - bool eventFilter(QObject* , QEvent*) { - return false; - } + bool eventFilter(QObject* , QEvent*) override; public slots: - void slotHelp(); + void slotHelp() override; }; #endif // KMERGETRANSACTIONSDLG_H diff --git a/kmymoney/dialogs/kmymoneyfileinfodlg.cpp b/kmymoney/dialogs/kmymoneyfileinfodlg.cpp index 10774548b..c34dcf7ad 100644 --- a/kmymoney/dialogs/kmymoneyfileinfodlg.cpp +++ b/kmymoney/dialogs/kmymoneyfileinfodlg.cpp @@ -1,95 +1,101 @@ /*************************************************************************** kmymoneyfileinfodlg.cpp - description ------------------- begin : Sun Oct 9 2005 copyright : (C) 2005 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kmymoneyfileinfodlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kmymoneyfileinfodlg.h" + #include #include "mymoneyfile.h" #include "mymoneyinstitution.h" #include "mymoneyaccount.h" -#include "mymoneyprice.h" #include "mymoneypayee.h" +#include "mymoneyprice.h" #include "mymoneyschedule.h" #include "mymoneytransaction.h" #include "mymoneytransactionfilter.h" #include "mymoneyenums.h" -KMyMoneyFileInfoDlg::KMyMoneyFileInfoDlg(QWidget *parent) - : KMyMoneyFileInfoDlgDecl(parent) +KMyMoneyFileInfoDlg::KMyMoneyFileInfoDlg(QWidget *parent) : + QDialog(parent), + ui(new Ui::KMyMoneyFileInfoDlg) { + ui->setupUi(this); // Now fill the fields with data - IMyMoneyStorage* storage = MyMoneyFile::instance()->storage(); + auto storage = MyMoneyFile::instance()->storage(); - m_creationDate->setText(storage->creationDate().toString(Qt::ISODate)); - m_lastModificationDate->setText(storage->lastModificationDate().toString(Qt::ISODate)); - m_baseCurrency->setText(storage->value("kmm-baseCurrency")); + ui->m_creationDate->setText(storage->creationDate().toString(Qt::ISODate)); + ui->m_lastModificationDate->setText(storage->lastModificationDate().toString(Qt::ISODate)); + ui->m_baseCurrency->setText(storage->value("kmm-baseCurrency")); - m_payeeCount->setText(QString("%1").arg(storage->payeeList().count())); - m_institutionCount->setText(QString("%1").arg(storage->institutionList().count())); + ui->m_payeeCount->setText(QString::fromLatin1("%1").arg(storage->payeeList().count())); + ui->m_institutionCount->setText(QString::fromLatin1("%1").arg(storage->institutionList().count())); QList a_list; storage->accountList(a_list); - m_accountCount->setText(QString("%1").arg(a_list.count())); + ui->m_accountCount->setText(QString::fromLatin1("%1").arg(a_list.count())); QMap accountMap; QMap accountMapClosed; QList::const_iterator it_a; for (it_a = a_list.constBegin(); it_a != a_list.constEnd(); ++it_a) { accountMap[(*it_a).accountType()] = accountMap[(*it_a).accountType()] + 1; accountMapClosed[(*it_a).accountType()] = accountMapClosed[(*it_a).accountType()] + 0; if ((*it_a).isClosed()) accountMapClosed[(*it_a).accountType()] = accountMapClosed[(*it_a).accountType()] + 1; } QMap::const_iterator it_m; for (it_m = accountMap.constBegin(); it_m != accountMap.constEnd(); ++it_m) { QTreeWidgetItem *item = new QTreeWidgetItem(); item->setText(0, MyMoneyAccount::accountTypeToString(it_m.key())); - item->setText(1, QString("%1").arg(*it_m)); - item->setText(2, QString("%1").arg(accountMapClosed[it_m.key()])); - m_accountView->invisibleRootItem()->addChild(item); + item->setText(1, QString::fromLatin1("%1").arg(*it_m)); + item->setText(2, QString::fromLatin1("%1").arg(accountMapClosed[it_m.key()])); + ui->m_accountView->invisibleRootItem()->addChild(item); } MyMoneyTransactionFilter filter; filter.setReportAllSplits(false); - m_transactionCount->setText(QString("%1").arg(storage->transactionList(filter).count())); + ui->m_transactionCount->setText(QString::fromLatin1("%1").arg(storage->transactionList(filter).count())); filter.setReportAllSplits(true); - m_splitCount->setText(QString("%1").arg(storage->transactionList(filter).count())); - m_scheduleCount->setText(QString("%1").arg(storage->scheduleList().count())); + ui->m_splitCount->setText(QString::fromLatin1("%1").arg(storage->transactionList(filter).count())); + ui->m_scheduleCount->setText(QString::fromLatin1("%1").arg(storage->scheduleList().count())); MyMoneyPriceList list = storage->priceList(); MyMoneyPriceList::const_iterator it_p; int pCount = 0; for (it_p = list.constBegin(); it_p != list.constEnd(); ++it_p) pCount += (*it_p).count(); - m_priceCount->setText(QString("%1").arg(pCount)); + ui->m_priceCount->setText(QString::fromLatin1("%1").arg(pCount)); } KMyMoneyFileInfoDlg::~KMyMoneyFileInfoDlg() { + delete ui; } diff --git a/kmymoney/dialogs/kmymoneyfileinfodlg.h b/kmymoney/dialogs/kmymoneyfileinfodlg.h index 849a69b1f..07531bbe9 100644 --- a/kmymoney/dialogs/kmymoneyfileinfodlg.h +++ b/kmymoney/dialogs/kmymoneyfileinfodlg.h @@ -1,51 +1,52 @@ /*************************************************************************** kmymoneyfileinfodlg.h - description ------------------- begin : Sun Oct 9 2005 copyright : (C) 2005 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KMYMONEYFILEINFODLG_H #define KMYMONEYFILEINFODLG_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_kmymoneyfileinfodlgdecl.h" +namespace Ui { class KMyMoneyFileInfoDlg; } /** * @author Thomas Baumgart */ -class KMyMoneyFileInfoDlgDecl : public QDialog, public Ui::KMyMoneyFileInfoDlgDecl -{ -public: - KMyMoneyFileInfoDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; -class KMyMoneyFileInfoDlg : public KMyMoneyFileInfoDlgDecl +class KMyMoneyFileInfoDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KMyMoneyFileInfoDlg) + public: - KMyMoneyFileInfoDlg(QWidget *parent = 0); - virtual ~KMyMoneyFileInfoDlg(); + explicit KMyMoneyFileInfoDlg(QWidget *parent = nullptr); + ~KMyMoneyFileInfoDlg(); + +private: + Ui::KMyMoneyFileInfoDlg *ui; }; #endif diff --git a/kmymoney/dialogs/kmymoneyfileinfodlgdecl.ui b/kmymoney/dialogs/kmymoneyfileinfodlg.ui similarity index 97% rename from kmymoney/dialogs/kmymoneyfileinfodlgdecl.ui rename to kmymoney/dialogs/kmymoneyfileinfodlg.ui index 6a2d347a8..a943a608e 100644 --- a/kmymoney/dialogs/kmymoneyfileinfodlgdecl.ui +++ b/kmymoney/dialogs/kmymoneyfileinfodlg.ui @@ -1,324 +1,324 @@ - KMyMoneyFileInfoDlgDecl - + KMyMoneyFileInfoDlg + 0 0 398 456 File Information true true Created on false false Last modified on false false Base currency false false Payees false false Institutions false false Accounts/Categories false false Transactions false false Splits false false Schedules false false Prices false false false Type Total Closed Qt::Vertical QSizePolicy::Expanding 20 20 QFrame::HLine QFrame::Sunken QDialogButtonBox::Ok buttonBox rejected() - KMyMoneyFileInfoDlgDecl + KMyMoneyFileInfoDlg reject() 404 454 422 400 buttonBox accepted() - KMyMoneyFileInfoDlgDecl + KMyMoneyFileInfoDlg accept() 336 453 356 402 diff --git a/kmymoney/dialogs/kmymoneypricedlg.cpp b/kmymoney/dialogs/kmymoneypricedlg.cpp index d6bc5081d..09d4c0e05 100644 --- a/kmymoney/dialogs/kmymoneypricedlg.cpp +++ b/kmymoney/dialogs/kmymoneypricedlg.cpp @@ -1,329 +1,351 @@ /*************************************************************************** kmymoneypricedlg.cpp ------------------- begin : Wed Nov 24 2004 copyright : (C) 2000-2004 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kmymoneypricedlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include -#include #include // ---------------------------------------------------------------------------- // KDE Includes -#include #include #include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kmymoneypricedlg.h" +#include "ui_kupdatestockpricedlg.h" + #include "kupdatestockpricedlg.h" #include "kcurrencycalculator.h" #include "mymoneyprice.h" #include "kequitypriceupdatedlg.h" #include "kmymoneycurrencyselector.h" #include "mymoneyfile.h" #include "mymoneyaccount.h" #include "mymoneysecurity.h" #include "mymoneymoney.h" #include "kmymoneyutils.h" #include "kpricetreeitem.h" #include "icons/icons.h" using namespace Icons; +class KMyMoneyPriceDlgPrivate +{ + Q_DISABLE_COPY(KMyMoneyPriceDlgPrivate) + Q_DECLARE_PUBLIC(KMyMoneyPriceDlg) + +public: + KMyMoneyPriceDlgPrivate(KMyMoneyPriceDlg *qq) : + q_ptr(qq), + ui(new Ui::KMyMoneyPriceDlg), + m_searchWidget(nullptr) + { + } + + ~KMyMoneyPriceDlgPrivate() + { + delete ui; + } + + KMyMoneyPriceDlg *q_ptr; + Ui::KMyMoneyPriceDlg *ui; + QTreeWidgetItem* m_currentItem; + /** + * Search widget for the list + */ + KTreeWidgetSearchLineWidget* m_searchWidget; + QMap m_stockNameMap; +}; + KMyMoneyPriceDlg::KMyMoneyPriceDlg(QWidget* parent) : - KMyMoneyPriceDlgDecl(parent) + QDialog(parent), + d_ptr(new KMyMoneyPriceDlgPrivate(this)) { - QVBoxLayout *mainLayout = new QVBoxLayout; - setLayout(mainLayout); - mainLayout->addWidget(m_layoutWidget); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - mainLayout->addWidget(buttonBox); + Q_D(KMyMoneyPriceDlg); + d->ui->setupUi(this); // create the searchline widget // and insert it into the existing layout - m_searchWidget = new KTreeWidgetSearchLineWidget(this, m_priceList); - m_searchWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); - m_listLayout->insertWidget(0, m_searchWidget); - - m_priceList->header()->setSortIndicator(0, Qt::AscendingOrder); - m_priceList->header()->setStretchLastSection(true); - m_priceList->setContextMenuPolicy(Qt::CustomContextMenu); - - KGuiItem removeButtonItem(i18n("&Delete"), - QIcon::fromTheme(g_Icons[Icon::EditDelete]), - i18n("Delete this entry"), - i18n("Remove this price item from the file")); - KGuiItem::assign(m_deleteButton, removeButtonItem); - - KGuiItem newButtonItem(i18nc("New price entry", "&New"), - QIcon::fromTheme(g_Icons[Icon::DocumentNew]), - i18n("Add a new entry"), - i18n("Create a new price entry.")); - KGuiItem::assign(m_newButton, newButtonItem); - - KGuiItem editButtonItem(i18n("&Edit"), - QIcon::fromTheme(g_Icons[Icon::DocumentEdit]), - i18n("Modify the selected entry"), - i18n("Change the details of selected price information.")); - KGuiItem::assign(m_editButton, editButtonItem); - - m_onlineQuoteButton->setIcon(KMyMoneyUtils::overlayIcon(g_Icons[Icon::ViewInvestment], g_Icons[Icon::Download])); - - connect(m_editButton, SIGNAL(clicked()), this, SLOT(slotEditPrice())); - connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(slotDeletePrice())); - connect(m_newButton, SIGNAL(clicked()), this, SLOT(slotNewPrice())); - connect(m_priceList, SIGNAL(itemSelectionChanged()), this, SLOT(slotSelectPrice())); - connect(m_onlineQuoteButton, SIGNAL(clicked()), this, SLOT(slotOnlinePriceUpdate())); - connect(m_priceList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotOpenContextMenu(QPoint))); - - connect(m_showAllPrices, SIGNAL(toggled(bool)), this, SLOT(slotLoadWidgets())); - connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); + d->m_searchWidget = new KTreeWidgetSearchLineWidget(this, d->ui->m_priceList); + d->m_searchWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); + + d->ui->m_listLayout->insertWidget(0, d->m_searchWidget); + + d->ui->m_priceList->header()->setSortIndicator(0, Qt::AscendingOrder); + d->ui->m_priceList->header()->setStretchLastSection(true); + d->ui->m_priceList->setContextMenuPolicy(Qt::CustomContextMenu); + + d->ui->m_deleteButton->setIcon(QIcon::fromTheme(g_Icons[Icon::EditDelete])); + d->ui->m_newButton->setIcon(QIcon::fromTheme(g_Icons[Icon::DocumentNew])); + d->ui->m_editButton->setIcon(QIcon::fromTheme(g_Icons[Icon::DocumentEdit])); + + d->ui->m_onlineQuoteButton->setIcon(KMyMoneyUtils::overlayIcon(g_Icons[Icon::ViewInvestment], g_Icons[Icon::Download])); + + connect(d->ui->m_editButton, &QAbstractButton::clicked, this, &KMyMoneyPriceDlg::slotEditPrice); + connect(d->ui->m_deleteButton, &QAbstractButton::clicked, this, &KMyMoneyPriceDlg::slotDeletePrice); + connect(d->ui->m_newButton, &QAbstractButton::clicked, this, &KMyMoneyPriceDlg::slotNewPrice); + connect(d->ui->m_priceList, &QTreeWidget::itemSelectionChanged, this, &KMyMoneyPriceDlg::slotSelectPrice); + connect(d->ui->m_onlineQuoteButton, &QAbstractButton::clicked, this, &KMyMoneyPriceDlg::slotOnlinePriceUpdate); + connect(d->ui->m_priceList, &QWidget::customContextMenuRequested, this, &KMyMoneyPriceDlg::slotOpenContextMenu); + + connect(d->ui->m_showAllPrices, &QAbstractButton::toggled, this, &KMyMoneyPriceDlg::slotLoadWidgets); + connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, this, &KMyMoneyPriceDlg::slotLoadWidgets); slotLoadWidgets(); slotSelectPrice(); } KMyMoneyPriceDlg::~KMyMoneyPriceDlg() { + Q_D(KMyMoneyPriceDlg); + delete d; } void KMyMoneyPriceDlg::slotLoadWidgets() { - MyMoneyFile* file = MyMoneyFile::instance(); + Q_D(KMyMoneyPriceDlg); + auto file = MyMoneyFile::instance(); //clear the list and disable the sorting while it loads the widgets, for performance - m_priceList->setSortingEnabled(false); - m_priceList->clear(); - m_stockNameMap.clear(); + d->ui->m_priceList->setSortingEnabled(false); + d->ui->m_priceList->clear(); + d->m_stockNameMap.clear(); //load the currencies for investments, which we'll need later QList accList; file->accountList(accList); QList::const_iterator acc_it; for (acc_it = accList.constBegin(); acc_it != accList.constEnd(); ++acc_it) { if ((*acc_it).isInvest()) { - if (m_stockNameMap.contains((*acc_it).currencyId())) { - m_stockNameMap[(*acc_it).currencyId()] = QString(m_stockNameMap.value((*acc_it).currencyId()) + ", " + (*acc_it).name()); + if (d->m_stockNameMap.contains((*acc_it).currencyId())) { + d->m_stockNameMap[(*acc_it).currencyId()] = QString(d->m_stockNameMap.value((*acc_it).currencyId()) + ", " + (*acc_it).name()); } else { - m_stockNameMap[(*acc_it).currencyId()] = (*acc_it).name(); + d->m_stockNameMap[(*acc_it).currencyId()] = (*acc_it).name(); } } } //get the price list MyMoneyPriceList list = file->priceList(); MyMoneyPriceList::ConstIterator it_allPrices; for (it_allPrices = list.constBegin(); it_allPrices != list.constEnd(); ++it_allPrices) { MyMoneyPriceEntries::ConstIterator it_priceItem; - if (m_showAllPrices->isChecked()) { + if (d->ui->m_showAllPrices->isChecked()) { for (it_priceItem = (*it_allPrices).constBegin(); it_priceItem != (*it_allPrices).constEnd(); ++it_priceItem) { loadPriceItem(*it_priceItem); } } else { //if it doesn't show all prices, it only shows the most recent occurrence for each price if ((*it_allPrices).count() > 0) { //the prices for each currency are ordered by date in ascending order //it gets the last item of the item, which is supposed to be the most recent price it_priceItem = (*it_allPrices).constEnd(); --it_priceItem; loadPriceItem(*it_priceItem); } } } //reenable sorting and sort by the commodity column - m_priceList->setSortingEnabled(true); - m_priceList->sortByColumn(KPriceTreeItem::ePriceCommodity); + d->ui->m_priceList->setSortingEnabled(true); + d->ui->m_priceList->sortByColumn(KPriceTreeItem::ePriceCommodity); //update the search widget so the list gets refreshed correctly if it was being filtered - if (!m_searchWidget->searchLine()->text().isEmpty()) - m_searchWidget->searchLine()->updateSearch(m_searchWidget->searchLine()->text()); + if (!d->m_searchWidget->searchLine()->text().isEmpty()) + d->m_searchWidget->searchLine()->updateSearch(d->m_searchWidget->searchLine()->text()); } QTreeWidgetItem* KMyMoneyPriceDlg::loadPriceItem(const MyMoneyPrice& basePrice) { + Q_D(KMyMoneyPriceDlg); MyMoneySecurity from, to; - MyMoneyPrice price = MyMoneyPrice(basePrice); + auto price = MyMoneyPrice(basePrice); - KPriceTreeItem* priceTreeItem = new KPriceTreeItem(m_priceList); + auto priceTreeItem = new KPriceTreeItem(d->ui->m_priceList); if (!price.isValid()) price = MyMoneyFile::instance()->price(price.from(), price.to(), price.date()); if (price.isValid()) { QString priceBase = price.to(); from = MyMoneyFile::instance()->security(price.from()); to = MyMoneyFile::instance()->security(price.to()); if (!to.isCurrency()) { from = MyMoneyFile::instance()->security(price.to()); to = MyMoneyFile::instance()->security(price.from()); priceBase = price.from(); } priceTreeItem->setData(KPriceTreeItem::ePriceCommodity, Qt::UserRole, QVariant::fromValue(price)); priceTreeItem->setText(KPriceTreeItem::ePriceCommodity, (from.isCurrency()) ? from.id() : from.tradingSymbol()); - priceTreeItem->setText(KPriceTreeItem::ePriceStockName, (from.isCurrency()) ? QString() : m_stockNameMap.value(from.id())); - priceTreeItem->setToolTip(KPriceTreeItem::ePriceStockName, (from.isCurrency()) ? QString() : m_stockNameMap.value(from.id())); + priceTreeItem->setText(KPriceTreeItem::ePriceStockName, (from.isCurrency()) ? QString() : d->m_stockNameMap.value(from.id())); + priceTreeItem->setToolTip(KPriceTreeItem::ePriceStockName, (from.isCurrency()) ? QString() : d->m_stockNameMap.value(from.id())); priceTreeItem->setText(KPriceTreeItem::ePriceCurrency, to.id()); priceTreeItem->setText(KPriceTreeItem::ePriceDate, QLocale().toString(price.date(), QLocale::ShortFormat)); priceTreeItem->setData(KPriceTreeItem::ePriceDate, KPriceTreeItem::OrderRole, QVariant(price.date())); priceTreeItem->setText(KPriceTreeItem::ePricePrice, price.rate(priceBase).formatMoney("", from.pricePrecision())); priceTreeItem->setTextAlignment(KPriceTreeItem::ePricePrice, Qt::AlignRight | Qt::AlignVCenter); priceTreeItem->setData(KPriceTreeItem::ePricePrice, KPriceTreeItem::OrderRole, QVariant::fromValue(price.rate(priceBase))); priceTreeItem->setText(KPriceTreeItem::ePriceSource, price.source()); } return priceTreeItem; } void KMyMoneyPriceDlg::slotSelectPrice() { + Q_D(KMyMoneyPriceDlg); QTreeWidgetItem* item = 0; - if (m_priceList->selectedItems().count() > 0) { - item = m_priceList->selectedItems().at(0); + if (d->ui->m_priceList->selectedItems().count() > 0) { + item = d->ui->m_priceList->selectedItems().at(0); } - m_currentItem = item; - m_editButton->setEnabled(item != 0); + d->m_currentItem = item; + d->ui->m_editButton->setEnabled(item != 0); bool deleteEnabled = (item != 0); //if one of the selected entries is a default, then deleting is disabled - QList itemsList = m_priceList->selectedItems(); + QList itemsList = d->ui->m_priceList->selectedItems(); QList::const_iterator item_it; for (item_it = itemsList.constBegin(); item_it != itemsList.constEnd(); ++item_it) { MyMoneyPrice price = (*item_it)->data(0, Qt::UserRole).value(); if (price.source() == "KMyMoney") deleteEnabled = false; } - m_deleteButton->setEnabled(deleteEnabled); + d->ui->m_deleteButton->setEnabled(deleteEnabled); // Modification of automatically added entries is not allowed // Multiple entries cannot be edited at once if (item) { MyMoneyPrice price = item->data(0, Qt::UserRole).value(); if (price.source() == "KMyMoney" || itemsList.count() > 1) - m_editButton->setEnabled(false); + d->ui->m_editButton->setEnabled(false); emit selectObject(price); } } void KMyMoneyPriceDlg::slotNewPrice() { + Q_D(KMyMoneyPriceDlg); QPointer dlg = new KUpdateStockPriceDlg(this); try { - QTreeWidgetItem* item = m_priceList->currentItem(); + auto item = d->ui->m_priceList->currentItem(); if (item) { MyMoneySecurity security; security = MyMoneyFile::instance()->security(item->data(0, Qt::UserRole).value().from()); - dlg->m_security->setSecurity(security); + dlg->ui->m_security->setSecurity(security); security = MyMoneyFile::instance()->security(item->data(0, Qt::UserRole).value().to()); - dlg->m_currency->setSecurity(security); + dlg->ui->m_currency->setSecurity(security); } if (dlg->exec()) { - MyMoneyPrice price(dlg->m_security->security().id(), dlg->m_currency->security().id(), dlg->date(), MyMoneyMoney::ONE); + MyMoneyPrice price(dlg->ui->m_security->security().id(), dlg->ui->m_currency->security().id(), dlg->date(), MyMoneyMoney::ONE); QTreeWidgetItem* p = loadPriceItem(price); - m_priceList->setCurrentItem(p, true); + d->ui->m_priceList->setCurrentItem(p, true); // If the user cancels the following operation, we delete the new item // and re-select any previously selected one if (slotEditPrice() == Rejected) { delete p; if (item) - m_priceList->setCurrentItem(item, true); + d->ui->m_priceList->setCurrentItem(item, true); } } } catch (...) { delete dlg; throw; } delete dlg; } int KMyMoneyPriceDlg::slotEditPrice() { + Q_D(KMyMoneyPriceDlg); int rc = Rejected; - QTreeWidgetItem* item = m_priceList->currentItem(); + auto item = d->ui->m_priceList->currentItem(); if (item) { MyMoneySecurity from(MyMoneyFile::instance()->security(item->data(0, Qt::UserRole).value().from())); MyMoneySecurity to(MyMoneyFile::instance()->security(item->data(0, Qt::UserRole).value().to())); signed64 fract = MyMoneyMoney::precToDenom(from.pricePrecision()); QPointer calc = new KCurrencyCalculator(from, to, MyMoneyMoney::ONE, item->data(0, Qt::UserRole).value().rate(to.id()), item->data(0, Qt::UserRole).value().date(), fract, this); calc->setupPriceEditor(); rc = calc->exec(); delete calc; } return rc; } void KMyMoneyPriceDlg::slotDeletePrice() { - QList listItems = m_priceList->selectedItems(); + Q_D(KMyMoneyPriceDlg); + QList listItems = d->ui->m_priceList->selectedItems(); if (listItems.count() > 0) { if (KMessageBox::questionYesNo(this, i18np("Do you really want to delete the selected price entry?", "Do you really want to delete the selected price entries?", listItems.count()), i18n("Delete price information"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "DeletePrice") == KMessageBox::Yes) { MyMoneyFileTransaction ft; try { QList::const_iterator price_it; for (price_it = listItems.constBegin(); price_it != listItems.constEnd(); ++price_it) { MyMoneyFile::instance()->removePrice((*price_it)->data(0, Qt::UserRole).value()); } ft.commit(); } catch (const MyMoneyException &) { qDebug("Cannot delete price"); } } } } void KMyMoneyPriceDlg::slotOnlinePriceUpdate() { QPointer dlg = new KEquityPriceUpdateDlg(this); if (dlg->exec() == Accepted && dlg) dlg->storePrices(); delete dlg; } void KMyMoneyPriceDlg::slotOpenContextMenu(const QPoint& p) { - QTreeWidgetItem* item = m_priceList->itemAt(p); + Q_D(KMyMoneyPriceDlg); + auto item = d->ui->m_priceList->itemAt(p); if (item) { - m_priceList->setCurrentItem(item, QItemSelectionModel::ClearAndSelect); + d->ui->m_priceList->setCurrentItem(item, QItemSelectionModel::ClearAndSelect); emit openContextMenu(item->data(0, Qt::UserRole).value()); } } diff --git a/kmymoney/dialogs/kmymoneypricedlg.h b/kmymoney/dialogs/kmymoneypricedlg.h index c530e5f52..ee03d31fe 100644 --- a/kmymoney/dialogs/kmymoneypricedlg.h +++ b/kmymoney/dialogs/kmymoneypricedlg.h @@ -1,81 +1,72 @@ /*************************************************************************** kmymoneypricedlg.h ------------------- begin : Wed Nov 24 2004 copyright : (C) 2000-2004 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KMYMONEYPRICEDLG_H #define KMYMONEYPRICEDLG_H // ---------------------------------------------------------------------------- // QT Includes +#include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_kmymoneypricedlgdecl.h" - class MyMoneyPrice; -class KTreeWidgetSearchLineWidget; class QTreeWidgetItem; -class KMyMoneyPriceDlgDecl : public QDialog, public Ui::KMyMoneyPriceDlgDecl -{ -public: - KMyMoneyPriceDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; -class KMyMoneyPriceDlg : public KMyMoneyPriceDlgDecl +class KMyMoneyPriceDlgPrivate; +class KMyMoneyPriceDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KMyMoneyPriceDlg) + public: - KMyMoneyPriceDlg(QWidget* parent); + explicit KMyMoneyPriceDlg(QWidget* parent); ~KMyMoneyPriceDlg(); private: QTreeWidgetItem* loadPriceItem(const MyMoneyPrice& basePrice); protected slots: void slotSelectPrice(); void slotNewPrice(); void slotDeletePrice(); int slotEditPrice(); void slotLoadWidgets(); void slotOnlinePriceUpdate(); void slotOpenContextMenu(const QPoint& p); signals: void openContextMenu(const MyMoneyPrice& price); void selectObject(const MyMoneyPrice& price); private: - QTreeWidgetItem* m_currentItem; - /** - * Search widget for the list - */ - KTreeWidgetSearchLineWidget* m_searchWidget; - QMap m_stockNameMap; + KMyMoneyPriceDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KMyMoneyPriceDlg) }; #endif // KMYMONEYPRICEDLG_H diff --git a/kmymoney/dialogs/kmymoneypricedlg.ui b/kmymoney/dialogs/kmymoneypricedlg.ui new file mode 100644 index 000000000..491e53be3 --- /dev/null +++ b/kmymoney/dialogs/kmymoneypricedlg.ui @@ -0,0 +1,212 @@ + + + KMyMoneyPriceDlg + + + + 0 + 0 + 806 + 440 + + + + Price Editor + + + + + + + + + + + + + 1 + 1 + + + + Remove this price item from the file + + + QAbstractItemView::ExtendedSelection + + + false + + + true + + + + Commodity + + + + + Stock Name + + + + + Currency + + + + + Date + + + + + Price + + + + + Source + + + + + + + + Show all stored prices + + + + + + + + + + + Add a new entry + + + Create a new price entry. + + + New + + + + + + + Modify the selected entry + + + Change the details of selected price information. + + + Modify + + + + + + + Online Quotes + + + + + + + Delete this entry + + + Delete + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 21 + 150 + + + + + + + + + + + + QDialogButtonBox::Close|QDialogButtonBox::Ok + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + + + + m_newButton + m_editButton + m_deleteButton + m_onlineQuoteButton + + + + + buttonBox + accepted() + KMyMoneyPriceDlg + accept() + + + 186 + 297 + + + 402 + 219 + + + + + buttonBox + rejected() + KMyMoneyPriceDlg + reject() + + + 186 + 297 + + + 402 + 219 + + + + + diff --git a/kmymoney/dialogs/kmymoneypricedlgdecl.ui b/kmymoney/dialogs/kmymoneypricedlgdecl.ui deleted file mode 100644 index 6112b1d71..000000000 --- a/kmymoney/dialogs/kmymoneypricedlgdecl.ui +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - KMyMoneyPriceDlgDecl - - - - 0 - 0 - 806 - 440 - - - - Price Editor - - - - - - - - - - - - 1 - 1 - - - - false - - - true - - - QAbstractItemView::ExtendedSelection - - - - Commodity - - - - - Stock Name - - - - - Currency - - - - - Date - - - - - Price - - - - - Source - - - - - - - - Show all stored prices - - - - - - - - - - - New - - - - - - - Modify - - - - - - - Online Quotes - - - - - - - Delete - - - - - - - - 21 - 150 - - - - QSizePolicy::Expanding - - - Qt::Vertical - - - - - - - - - - - QFrame::HLine - - - QFrame::Sunken - - - - - - - - - - QDialog - QDialog -
kdialog.h
-
-
- - m_newButton - m_editButton - m_deleteButton - m_onlineQuoteButton - - - - 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000030149444154789cb59531681b5718c77f0e377c070e3c810a3a70e0041eac51852e0a19e45134830a1d9a4c69a04bc8928e990a693a640e1d0c8642b08742321894c1507991b484c890902bb8701a047760c3bd21701fe4201dde49b6a41a32b8df72dcbbeffdbefffbbfefbd5b1b0c07cce266ebe667ae2006c3c1dada0cdc3be87d6e6c35b0d692a409d9c7ec8b20d65ae29398d19b1114e7e3de4ce98b3f5e10dc0053cf0951b4506496e1b964bf7ce6c585d9054c62d01d617ca48be0596553cf496d8f2c8b01c5f795fc93904e85ec4c01a152857a5d9175d0b2805c872080f18595ccc1499a10a225d4e2fbc2877786fe81253ab6c04c8d106e09db5d43ab0d146e5c64d1a23938fb98a185cea1c33eecfd9eba49eb427dcb201e245365f2b7b2fb5b4a3a31dcb927178afe07d86901df870fefa4842aed6f6b74ba42e52b4014d580e1eb9cbd9d94de7e4aad16d2f9be02d805f0b5e532f927a1ffcacea1777f122a8105b164a7c25faf323a5d9f1f1fd600e1e5bec59e2d4b5c7ef5209d0ad17b8b31864e57c0b3e0815ac3ee33253ab664a770ff5185d1a1cb8d2267d3e58aa1dc7d2508cbe597d0e74fdd269aaaf0f52d414c4ea3e9762c996869e42560d7a72e41c4799a2586e74f95e8d8151481fa86efbe7b3398ac58b1a2b8527589f15451ad303ac2293542ad6648a796278f13a27185e4c4754310facb98c53a79e19a3fdc1426ff28c3d7399d1f7cb25343eb96106cf83c790ce9c4f2eb831855c55485663327992eb6dc8a6259874ed700b0b793323cccb9ffa842b30d6133e3e75fea989ac15a8b16ca76b746b0b92278d919774c5b6d48a78697fb29bbcf52468742a32120909c24e899ce67beed5be2db01e22d1e9485bb620e47f9ee9e606a21bd3f5d3744c7e7c54d55e87443867d8b554515ac5db4620e8e4f62263170fd1cdee90aad7640141992891b0f367c9adfe4049bb07d3b7022bd8c687c0978f46684ee084150b65ac1fcca94591b7a90a496e4c095164fb016a2b192a497795cc0f84817aebe25f7bf70ccc54a575c555c03f78ffa5fc0570d1f0c076bff0232285a0901e2257b0000000049454e44ae426082 - - -
diff --git a/kmymoney/dialogs/kmymoneysplittable.cpp b/kmymoney/dialogs/kmymoneysplittable.cpp index 0db971b50..1bd2a04e6 100644 --- a/kmymoney/dialogs/kmymoneysplittable.cpp +++ b/kmymoney/dialogs/kmymoneysplittable.cpp @@ -1,971 +1,1085 @@ /*************************************************************************** kmymoneysplittable.cpp - description ------------------- begin : Thu Jan 10 2002 copyright : (C) 2000-2002 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kmymoneysplittable.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include #include #include #include #include #include #include +#include +#include +#include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "mymoneysplit.h" +#include "mymoneytransaction.h" +#include "mymoneyaccount.h" #include "mymoneyfile.h" #include "mymoneyprice.h" #include "kmymoneyedit.h" #include "kmymoneycategory.h" #include "kmymoneyaccountselector.h" #include "kmymoneylineedit.h" #include "mymoneysecurity.h" #include "kmymoneyglobalsettings.h" #include "kcurrencycalculator.h" #include "mymoneyutils.h" #include "icons.h" using namespace Icons; -kMyMoneySplitTable::kMyMoneySplitTable(QWidget *parent) : - QTableWidget(parent), +class KMyMoneySplitTablePrivate +{ + Q_DISABLE_COPY(KMyMoneySplitTablePrivate) + +public: + KMyMoneySplitTablePrivate() : m_currentRow(0), m_maxRows(0), m_precision(2), m_editCategory(0), m_editMemo(0), m_editAmount(0) + { + } + + ~KMyMoneySplitTablePrivate() + { + } + + /// the currently selected row (will be printed as selected) + int m_currentRow; + + /// the number of rows filled with data + int m_maxRows; + + MyMoneyTransaction m_transaction; + MyMoneyAccount m_account; + MyMoneySplit m_split; + MyMoneySplit m_hiddenSplit; + + /** + * This member keeps the precision for the values + */ + int m_precision; + + /** + * This member keeps a pointer to the context menu + */ + QMenu* m_contextMenu; + + /// keeps the QAction of the delete entry in the context menu + QAction* m_contextMenuDelete; + + /// keeps the QAction of the duplicate entry in the context menu + QAction* m_contextMenuDuplicate; + + /** + * This member contains a pointer to the input widget for the category. + * The widget will be created and destroyed dynamically in createInputWidgets() + * and destroyInputWidgets(). + */ + QPointer m_editCategory; + + /** + * This member contains a pointer to the input widget for the memo. + * The widget will be created and destroyed dynamically in createInputWidgets() + * and destroyInputWidgets(). + */ + QPointer m_editMemo; + + /** + * This member contains a pointer to the input widget for the amount. + * The widget will be created and destroyed dynamically in createInputWidgets() + * and destroyInputWidgets(). + */ + QPointer m_editAmount; + + /** + * This member keeps the tab order for the above widgets + */ + QWidgetList m_tabOrderWidgets; + + QPointer m_registerButtonFrame; + QPointer m_registerEnterButton; + QPointer m_registerCancelButton; + + QMap m_priceInfo; +}; + +KMyMoneySplitTable::KMyMoneySplitTable(QWidget *parent) : + QTableWidget(parent), + d_ptr(new KMyMoneySplitTablePrivate) { + Q_D(KMyMoneySplitTable); // used for custom coloring with the help of the application's stylesheet setObjectName(QLatin1String("splittable")); // setup the transactions table setRowCount(1); setColumnCount(3); QStringList labels; labels << i18n("Category") << i18n("Memo") << i18n("Amount"); setHorizontalHeaderLabels(labels); setSelectionMode(QAbstractItemView::SingleSelection); setSelectionBehavior(QAbstractItemView::SelectRows); int left, top, right, bottom; getContentsMargins(&left, &top, &right, &bottom); setContentsMargins(0, top, right, bottom); setFont(KMyMoneyGlobalSettings::listCellFont()); setAlternatingRowColors(true); verticalHeader()->hide(); horizontalHeader()->setSectionsMovable(false); horizontalHeader()->setFont(KMyMoneyGlobalSettings::listHeaderFont()); KConfigGroup grp = KSharedConfig::openConfig()->group("SplitTable"); QByteArray columns; columns = grp.readEntry("HeaderState", columns); horizontalHeader()->restoreState(columns); horizontalHeader()->setStretchLastSection(true); setShowGrid(KMyMoneyGlobalSettings::showGrid()); setEditTriggers(QAbstractItemView::NoEditTriggers); // setup the context menu - m_contextMenu = new QMenu(this); - m_contextMenu->setTitle(i18n("Split Options")); - m_contextMenu->setIcon(QIcon::fromTheme(g_Icons[Icon::ViewFinancialTransfer])); - m_contextMenu->addAction(QIcon::fromTheme(g_Icons[Icon::DocumentEdit]), i18n("Edit..."), this, SLOT(slotStartEdit())); - m_contextMenuDuplicate = m_contextMenu->addAction(QIcon::fromTheme(g_Icons[Icon::EditCopy]), i18nc("To duplicate a split", "Duplicate"), this, SLOT(slotDuplicateSplit())); - m_contextMenuDelete = m_contextMenu->addAction(QIcon::fromTheme(g_Icons[Icon::EditDelete]), + d->m_contextMenu = new QMenu(this); + d->m_contextMenu->setTitle(i18n("Split Options")); + d->m_contextMenu->setIcon(QIcon::fromTheme(g_Icons[Icon::ViewFinancialTransfer])); + d->m_contextMenu->addAction(QIcon::fromTheme(g_Icons[Icon::DocumentEdit]), i18n("Edit..."), this, SLOT(slotStartEdit())); + d->m_contextMenuDuplicate = d->m_contextMenu->addAction(QIcon::fromTheme(g_Icons[Icon::EditCopy]), i18nc("To duplicate a split", "Duplicate"), this, SLOT(slotDuplicateSplit())); + d->m_contextMenuDelete = d->m_contextMenu->addAction(QIcon::fromTheme(g_Icons[Icon::EditDelete]), i18n("Delete..."), this, SLOT(slotDeleteSplit())); - connect(this, SIGNAL(clicked(QModelIndex)), - this, SLOT(slotSetFocus(QModelIndex))); + connect(this, &QAbstractItemView::clicked, + this, static_cast(&KMyMoneySplitTable::slotSetFocus)); - connect(this, SIGNAL(transactionChanged(MyMoneyTransaction)), - this, SLOT(slotUpdateData(MyMoneyTransaction))); + connect(this, &KMyMoneySplitTable::transactionChanged, + this, &KMyMoneySplitTable::slotUpdateData); installEventFilter(this); } -kMyMoneySplitTable::~kMyMoneySplitTable() +KMyMoneySplitTable::~KMyMoneySplitTable() { - KConfigGroup grp = KSharedConfig::openConfig()->group("SplitTable"); + Q_D(KMyMoneySplitTable); + auto grp = KSharedConfig::openConfig()->group("SplitTable"); QByteArray columns = horizontalHeader()->saveState(); grp.writeEntry("HeaderState", columns); grp.sync(); + delete d; } -int kMyMoneySplitTable::currentRow() const +int KMyMoneySplitTable::currentRow() const { - return m_currentRow; + Q_D(const KMyMoneySplitTable); + return d->m_currentRow; } -void kMyMoneySplitTable::setup(const QMap& priceInfo, int precision) +void KMyMoneySplitTable::setup(const QMap& priceInfo, int precision) { - m_priceInfo = priceInfo; - m_precision = precision; + Q_D(KMyMoneySplitTable); + d->m_priceInfo = priceInfo; + d->m_precision = precision; } -bool kMyMoneySplitTable::eventFilter(QObject *o, QEvent *e) +bool KMyMoneySplitTable::eventFilter(QObject *o, QEvent *e) { + Q_D(KMyMoneySplitTable); // MYMONEYTRACER(tracer); QKeyEvent *k = static_cast(e); bool rc = false; int row = currentRow(); int lines = viewport()->height() / rowHeight(0); if (e->type() == QEvent::KeyPress && !isEditMode()) { rc = true; switch (k->key()) { case Qt::Key_Up: if (row) slotSetFocus(model()->index(row - 1, 0)); break; case Qt::Key_Down: - if (row < m_transaction.splits().count() - 1) + if (row < d->m_transaction.splits().count() - 1) slotSetFocus(model()->index(row + 1, 0)); break; case Qt::Key_Home: slotSetFocus(model()->index(0, 0)); break; case Qt::Key_End: - slotSetFocus(model()->index(m_transaction.splits().count() - 1, 0)); + slotSetFocus(model()->index(d->m_transaction.splits().count() - 1, 0)); break; case Qt::Key_PageUp: if (lines) { while (lines-- > 0 && row) --row; slotSetFocus(model()->index(row, 0)); } break; case Qt::Key_PageDown: - if (row < m_transaction.splits().count() - 1) { - while (lines-- > 0 && row < m_transaction.splits().count() - 1) + if (row < d->m_transaction.splits().count() - 1) { + while (lines-- > 0 && row < d->m_transaction.splits().count() - 1) ++row; slotSetFocus(model()->index(row, 0)); } break; case Qt::Key_Delete: slotDeleteSplit(); break; case Qt::Key_Return: case Qt::Key_Enter: - if (row < m_transaction.splits().count() - 1 + if (row < d->m_transaction.splits().count() - 1 && KMyMoneyGlobalSettings::enterMovesBetweenFields()) { slotStartEdit(); } else emit returnPressed(); break; case Qt::Key_Escape: emit escapePressed(); break; case Qt::Key_F2: slotStartEdit(); break; default: rc = true; // duplicate split if (Qt::Key_C == k->key() && Qt::ControlModifier == k->modifiers()) { slotDuplicateSplit(); // new split } else if (Qt::Key_Insert == k->key() && Qt::ControlModifier == k->modifiers()) { - slotSetFocus(model()->index(m_transaction.splits().count() - 1, 0)); + slotSetFocus(model()->index(d->m_transaction.splits().count() - 1, 0)); slotStartEdit(); } else if (k->text()[ 0 ].isPrint()) { KMyMoneyCategory* cat = createEditWidgets(false); if (cat) { kMyMoneyLineEdit *le = qobject_cast(cat->lineEdit()); if (le) { // make sure, the widget receives the key again // and does not select the text this time le->setText(k->text()); le->end(false); le->deselect(); le->skipSelectAll(true); le->setFocus(); } } } break; } } else if (e->type() == QEvent::KeyPress && isEditMode()) { bool terminate = true; rc = true; switch (k->key()) { // suppress the F2 functionality to start editing in inline edit mode case Qt::Key_F2: // suppress the cursor movement in inline edit mode case Qt::Key_Up: case Qt::Key_Down: case Qt::Key_PageUp: case Qt::Key_PageDown: break; case Qt::Key_Return: case Qt::Key_Enter: // we cannot call the slot directly, as it destroys the caller of // this method :-( So we let the event handler take care of calling // the respective slot using a timeout. For a KLineEdit derived object // it could be, that at this point the user selected a value from // a completion list. In this case, we close the completion list and // do not end editing of the transaction. if (o->inherits("KLineEdit")) { KLineEdit* le = dynamic_cast(o); KCompletionBox* box = le->completionBox(false); if (box && box->isVisible()) { terminate = false; le->completionBox(false)->hide(); } } // in case we have the 'enter moves focus between fields', we need to simulate // a TAB key when the object 'o' points to the category or memo field. if (KMyMoneyGlobalSettings::enterMovesBetweenFields()) { - if (o == m_editCategory->lineEdit() || o == m_editMemo) { + if (o == d->m_editCategory->lineEdit() || o == d->m_editMemo) { terminate = false; QKeyEvent evt(e->type(), Qt::Key_Tab, k->modifiers(), QString(), k->isAutoRepeat(), k->count()); QApplication::sendEvent(o, &evt); } } if (terminate) { QTimer::singleShot(0, this, SLOT(slotEndEditKeyboard())); } break; case Qt::Key_Escape: // we cannot call the slot directly, as it destroys the caller of // this method :-( So we let the event handler take care of calling // the respective slot using a timeout. QTimer::singleShot(0, this, SLOT(slotCancelEdit())); break; default: rc = false; break; } } else if (e->type() == QEvent::KeyRelease && !isEditMode()) { // for some reason, we only see a KeyRelease event of the Menu key // here. In other locations (e.g. Register::eventFilter()) we see // a KeyPress event. Strange. (ipwizard - 2008-05-10) switch (k->key()) { case Qt::Key_Menu: // if the very last entry is selected, the delete // operation is not available otherwise it is - m_contextMenuDelete->setEnabled( - row < m_transaction.splits().count() - 1); - m_contextMenuDuplicate->setEnabled( - row < m_transaction.splits().count() - 1); + d->m_contextMenuDelete->setEnabled( + row < d->m_transaction.splits().count() - 1); + d->m_contextMenuDuplicate->setEnabled( + row < d->m_transaction.splits().count() - 1); - m_contextMenu->exec(QCursor::pos()); + d->m_contextMenu->exec(QCursor::pos()); rc = true; break; default: break; } } // if the event has not been processed here, forward it to // the base class implementation if it's not a key event if (rc == false) { if (e->type() != QEvent::KeyPress && e->type() != QEvent::KeyRelease) { rc = QTableWidget::eventFilter(o, e); } } return rc; } -void kMyMoneySplitTable::slotSetFocus(const QModelIndex& index, int button) +void KMyMoneySplitTable::slotSetFocus(const QModelIndex& index) +{ + slotSetFocus(index, Qt::LeftButton); +} + +void KMyMoneySplitTable::slotSetFocus(const QModelIndex& index, int button) { + Q_D(KMyMoneySplitTable); MYMONEYTRACER(tracer); - int row = index.row(); + auto row = index.row(); // adjust row to used area - if (row > m_transaction.splits().count() - 1) - row = m_transaction.splits().count() - 1; + if (row > d->m_transaction.splits().count() - 1) + row = d->m_transaction.splits().count() - 1; if (row < 0) row = 0; // make sure the row will be on the screen scrollTo(model()->index(row, 0)); if (isEditMode()) { // in edit mode? if (isEditSplitValid() && KMyMoneyGlobalSettings::focusChangeIsEnter()) endEdit(false/*keyboard driven*/, false/*set focus to next row*/); else slotCancelEdit(); } if (button == Qt::LeftButton) { // left mouse button if (row != currentRow()) { // setup new current row and update visible selection selectRow(row); - slotUpdateData(m_transaction); + slotUpdateData(d->m_transaction); } } else if (button == Qt::RightButton) { // context menu is only available when cursor is on // an existing transaction or the first line after this area if (row == index.row()) { // setup new current row and update visible selection selectRow(row); - slotUpdateData(m_transaction); + slotUpdateData(d->m_transaction); // if the very last entry is selected, the delete // operation is not available otherwise it is - m_contextMenuDelete->setEnabled( - row < m_transaction.splits().count() - 1); - m_contextMenuDuplicate->setEnabled( - row < m_transaction.splits().count() - 1); + d->m_contextMenuDelete->setEnabled( + row < d->m_transaction.splits().count() - 1); + d->m_contextMenuDuplicate->setEnabled( + row < d->m_transaction.splits().count() - 1); - m_contextMenu->exec(QCursor::pos()); + d->m_contextMenu->exec(QCursor::pos()); } } } -void kMyMoneySplitTable::mousePressEvent(QMouseEvent* e) +void KMyMoneySplitTable::mousePressEvent(QMouseEvent* e) { slotSetFocus(indexAt(e->pos()), e->button()); } /* turn off QTable behaviour */ -void kMyMoneySplitTable::mouseReleaseEvent(QMouseEvent* /* e */) +void KMyMoneySplitTable::mouseReleaseEvent(QMouseEvent* /* e */) { } -void kMyMoneySplitTable::mouseDoubleClickEvent(QMouseEvent *e) +void KMyMoneySplitTable::mouseDoubleClickEvent(QMouseEvent *e) { + Q_D(KMyMoneySplitTable); MYMONEYTRACER(tracer); int col = columnAt(e->pos().x()); slotSetFocus(model()->index(rowAt(e->pos().y()), col), e->button()); createEditWidgets(false); QLineEdit* editWidget = 0; //krazy:exclude=qmethods switch (col) { case 0: - editWidget = m_editCategory->lineEdit(); + editWidget = d->m_editCategory->lineEdit(); break; case 1: - editWidget = m_editMemo; + editWidget = d->m_editMemo; break; case 2: - editWidget = m_editAmount->lineedit(); + editWidget = d->m_editAmount->lineedit(); break; default: break; } if (editWidget) { editWidget->setFocus(); editWidget->selectAll(); } } -void kMyMoneySplitTable::selectRow(int row) +void KMyMoneySplitTable::selectRow(int row) { + Q_D(KMyMoneySplitTable); MYMONEYTRACER(tracer); - if (row > m_maxRows) - row = m_maxRows; - m_currentRow = row; + if (row > d->m_maxRows) + row = d->m_maxRows; + d->m_currentRow = row; QTableWidget::selectRow(row); - QList list = getSplits(m_transaction); + QList list = getSplits(d->m_transaction); if (row < list.count()) - m_split = list[row]; + d->m_split = list[row]; else - m_split = MyMoneySplit(); + d->m_split = MyMoneySplit(); } -void kMyMoneySplitTable::setRowCount(int irows) +void KMyMoneySplitTable::setRowCount(int irows) { QTableWidget::setRowCount(irows); // determine row height according to the edit widgets // we use the category widget as the base QFontMetrics fm(KMyMoneyGlobalSettings::listCellFont()); int height = fm.lineSpacing() + 6; #if 0 // recalculate row height hint KMyMoneyCategory cat; height = qMax(cat.sizeHint().height(), height); #endif verticalHeader()->setUpdatesEnabled(false); - for (int i = 0; i < irows; ++i) + for (auto i = 0; i < irows; ++i) verticalHeader()->resizeSection(i, height); verticalHeader()->setUpdatesEnabled(true); } -void kMyMoneySplitTable::setTransaction(const MyMoneyTransaction& t, const MyMoneySplit& s, const MyMoneyAccount& acc) +void KMyMoneySplitTable::setTransaction(const MyMoneyTransaction& t, const MyMoneySplit& s, const MyMoneyAccount& acc) { + Q_D(KMyMoneySplitTable); MYMONEYTRACER(tracer); - m_transaction = t; - m_account = acc; - m_hiddenSplit = s; + d->m_transaction = t; + d->m_account = acc; + d->m_hiddenSplit = s; selectRow(0); - slotUpdateData(m_transaction); + slotUpdateData(d->m_transaction); +} + +MyMoneyTransaction KMyMoneySplitTable::transaction() const +{ + Q_D(const KMyMoneySplitTable); + return d->m_transaction; } -const QList kMyMoneySplitTable::getSplits(const MyMoneyTransaction& t) const +QList KMyMoneySplitTable::getSplits(const MyMoneyTransaction& t) const { + Q_D(const KMyMoneySplitTable); // get list of splits QList list = t.splits(); // and ignore the one that should be hidden QList::Iterator it; for (it = list.begin(); it != list.end(); ++it) { - if ((*it).id() == m_hiddenSplit.id()) { + if ((*it).id() == d->m_hiddenSplit.id()) { list.erase(it); break; } } return list; } -void kMyMoneySplitTable::slotUpdateData(const MyMoneyTransaction& t) +void KMyMoneySplitTable::slotUpdateData(const MyMoneyTransaction& t) { + Q_D(KMyMoneySplitTable); MYMONEYTRACER(tracer); unsigned long numRows = 0; QTableWidgetItem* textItem; QList list = getSplits(t); updateTransactionTableSize(); // fill the part that is used by transactions QList::Iterator it; for (it = list.begin(); it != list.end(); ++it) { QString colText; MyMoneyMoney value = (*it).value(); if (!(*it).accountId().isEmpty()) { try { colText = MyMoneyFile::instance()->accountToCategory((*it).accountId()); } catch (const MyMoneyException &) { - qDebug("Unexpected exception in kMyMoneySplitTable::slotUpdateData()"); + qDebug("Unexpected exception in KMyMoneySplitTable::slotUpdateData()"); } } - QString amountTxt = value.formatMoney(m_account.fraction()); + QString amountTxt = value.formatMoney(d->m_account.fraction()); if (value == MyMoneyMoney::autoCalc) { amountTxt = i18n("will be calculated"); } if (colText.isEmpty() && (*it).memo().isEmpty() && value.isZero()) amountTxt.clear(); unsigned width = fontMetrics().width(amountTxt); kMyMoneyEdit* valfield = new kMyMoneyEdit(); valfield->setMinimumWidth(width); width = valfield->minimumSizeHint().width(); delete valfield; textItem = item(numRows, 0); if (textItem) textItem->setText(colText); else setItem(numRows, 0, new QTableWidgetItem(colText)); textItem = item(numRows, 1); if (textItem) textItem->setText((*it).memo()); else setItem(numRows, 1, new QTableWidgetItem((*it).memo())); textItem = item(numRows, 2); if (textItem) textItem->setText(amountTxt); else setItem(numRows, 2, new QTableWidgetItem(amountTxt)); item(numRows, 2)->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); ++numRows; } // now clean out the remainder of the table while (numRows < static_cast(rowCount())) { - for (int i = 0 ; i < 3; ++i) { + for (auto i = 0 ; i < 3; ++i) { textItem = item(numRows, i); if (textItem) textItem->setText(""); else setItem(numRows, i, new QTableWidgetItem("")); } item(numRows, 2)->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); ++numRows; } } -void kMyMoneySplitTable::updateTransactionTableSize() +void KMyMoneySplitTable::updateTransactionTableSize() { + Q_D(KMyMoneySplitTable); // get current size of transactions table int tableHeight = height(); - int splitCount = m_transaction.splits().count() - 1; + int splitCount = d->m_transaction.splits().count() - 1; if (splitCount < 0) splitCount = 0; // see if we need some extra lines to fill the current size with the grid int numExtraLines = (tableHeight / rowHeight(0)) - splitCount; if (numExtraLines < 2) numExtraLines = 2; setRowCount(splitCount + numExtraLines); - m_maxRows = splitCount; + d->m_maxRows = splitCount; } -void kMyMoneySplitTable::resizeEvent(QResizeEvent* ev) +void KMyMoneySplitTable::resizeEvent(QResizeEvent* ev) { QTableWidget::resizeEvent(ev); if (!isEditMode()) { // update the size of the transaction table only if a split is not being edited // otherwise the height of the editors would be altered in an undesired way updateTransactionTableSize(); } } -void kMyMoneySplitTable::slotDuplicateSplit() +void KMyMoneySplitTable::slotDuplicateSplit() { + Q_D(KMyMoneySplitTable); MYMONEYTRACER(tracer); - QList list = getSplits(m_transaction); - if (m_currentRow < list.count()) { - MyMoneySplit split = list[m_currentRow]; + QList list = getSplits(d->m_transaction); + if (d->m_currentRow < list.count()) { + MyMoneySplit split = list[d->m_currentRow]; split.clearId(); try { - m_transaction.addSplit(split); - emit transactionChanged(m_transaction); + d->m_transaction.addSplit(split); + emit transactionChanged(d->m_transaction); } catch (const MyMoneyException &e) { qDebug("Cannot duplicate split: %s", qPrintable(e.what())); } } } -void kMyMoneySplitTable::slotDeleteSplit() +void KMyMoneySplitTable::slotDeleteSplit() { + Q_D(KMyMoneySplitTable); MYMONEYTRACER(tracer); - QList list = getSplits(m_transaction); - if (m_currentRow < list.count()) { + QList list = getSplits(d->m_transaction); + if (d->m_currentRow < list.count()) { if (KMessageBox::warningContinueCancel(this, i18n("You are about to delete the selected split. " "Do you really want to continue?"), - i18n("KMyMoney"), - KGuiItem(i18n("Continue")) + i18n("KMyMoney") ) == KMessageBox::Continue) { try { - m_transaction.removeSplit(list[m_currentRow]); + d->m_transaction.removeSplit(list[d->m_currentRow]); // if we removed the last split, select the previous - if (m_currentRow && m_currentRow == list.count() - 1) - selectRow(m_currentRow - 1); + if (d->m_currentRow && d->m_currentRow == list.count() - 1) + selectRow(d->m_currentRow - 1); else - selectRow(m_currentRow); - emit transactionChanged(m_transaction); + selectRow(d->m_currentRow); + emit transactionChanged(d->m_transaction); } catch (const MyMoneyException &e) { qDebug("Cannot remove split: %s", qPrintable(e.what())); } } } } -KMyMoneyCategory* kMyMoneySplitTable::slotStartEdit() +KMyMoneyCategory* KMyMoneySplitTable::slotStartEdit() { MYMONEYTRACER(tracer); return createEditWidgets(true); } -void kMyMoneySplitTable::slotEndEdit() +void KMyMoneySplitTable::slotEndEdit() { endEdit(false); } -void kMyMoneySplitTable::slotEndEditKeyboard() +void KMyMoneySplitTable::slotEndEditKeyboard() { endEdit(true); } -void kMyMoneySplitTable::endEdit(bool keyboardDriven, bool setFocusToNextRow) +void KMyMoneySplitTable::endEdit(bool keyboardDriven, bool setFocusToNextRow) { - MyMoneyFile* file = MyMoneyFile::instance(); + Q_D(KMyMoneySplitTable); + auto file = MyMoneyFile::instance(); MYMONEYTRACER(tracer); - MyMoneySplit s1 = m_split; + MyMoneySplit s1 = d->m_split; if (!isEditSplitValid()) { KMessageBox::information(this, i18n("You need to assign a category to this split before it can be entered."), i18n("Enter split"), "EnterSplitWithEmptyCategory"); - m_editCategory->setFocus(); + d->m_editCategory->setFocus(); return; } bool needUpdate = false; - if (m_editCategory->selectedItem() != m_split.accountId()) { - s1.setAccountId(m_editCategory->selectedItem()); + if (d->m_editCategory->selectedItem() != d->m_split.accountId()) { + s1.setAccountId(d->m_editCategory->selectedItem()); needUpdate = true; } - if (m_editMemo->text() != m_split.memo()) { - s1.setMemo(m_editMemo->text()); + if (d->m_editMemo->text() != d->m_split.memo()) { + s1.setMemo(d->m_editMemo->text()); needUpdate = true; } - if (m_editAmount->value() != m_split.value()) { - s1.setValue(m_editAmount->value()); + if (d->m_editAmount->value() != d->m_split.value()) { + s1.setValue(d->m_editAmount->value()); needUpdate = true; } if (needUpdate) { if (!s1.value().isZero()) { MyMoneyAccount cat = file->account(s1.accountId()); - if (cat.currencyId() != m_transaction.commodity()) { + if (cat.currencyId() != d->m_transaction.commodity()) { MyMoneySecurity fromCurrency, toCurrency; MyMoneyMoney fromValue, toValue; - fromCurrency = file->security(m_transaction.commodity()); + fromCurrency = file->security(d->m_transaction.commodity()); toCurrency = file->security(cat.currencyId()); // determine the fraction required for this category int fract = toCurrency.smallestAccountFraction(); if (cat.accountType() == eMyMoney::Account::Cash) fract = toCurrency.smallestCashFraction(); // display only positive values to the user fromValue = s1.value().abs(); // if we had a price info in the beginning, we use it here - if (m_priceInfo.find(cat.currencyId()) != m_priceInfo.end()) { - toValue = (fromValue * m_priceInfo[cat.currencyId()]).convert(fract); + if (d->m_priceInfo.find(cat.currencyId()) != d->m_priceInfo.end()) { + toValue = (fromValue * d->m_priceInfo[cat.currencyId()]).convert(fract); } // if the shares are still 0, we need to change that if (toValue.isZero()) { const MyMoneyPrice &price = MyMoneyFile::instance()->price(fromCurrency.id(), toCurrency.id()); // if the price is valid calculate the shares. If it is invalid // assume a conversion rate of 1.0 if (price.isValid()) { toValue = (price.rate(toCurrency.id()) * fromValue).convert(fract); } else { toValue = fromValue; } } // now present all that to the user QPointer calc = new KCurrencyCalculator(fromCurrency, toCurrency, fromValue, toValue, - m_transaction.postDate(), + d->m_transaction.postDate(), fract, this); if (calc->exec() == QDialog::Rejected) { delete calc; return; } else { s1.setShares((s1.value() * calc->price()).convert(fract)); delete calc; } } else { s1.setShares(s1.value()); } } else s1.setShares(s1.value()); - m_split = s1; + d->m_split = s1; try { - if (m_split.id().isEmpty()) { - m_transaction.addSplit(m_split); + if (d->m_split.id().isEmpty()) { + d->m_transaction.addSplit(d->m_split); } else { - m_transaction.modifySplit(m_split); + d->m_transaction.modifySplit(d->m_split); } - emit transactionChanged(m_transaction); + emit transactionChanged(d->m_transaction); } catch (const MyMoneyException &e) { qDebug("Cannot add/modify split: %s", qPrintable(e.what())); } } this->setFocus(); destroyEditWidgets(); if (setFocusToNextRow) { slotSetFocus(model()->index(currentRow() + 1, 0)); } // if we still have more splits, we start editing right away // in case we have selected 'enter moves between fields' if (keyboardDriven - && currentRow() < m_transaction.splits().count() - 1 + && currentRow() < d->m_transaction.splits().count() - 1 && KMyMoneyGlobalSettings::enterMovesBetweenFields()) { slotStartEdit(); } } -void kMyMoneySplitTable::slotCancelEdit() +void KMyMoneySplitTable::slotCancelEdit() { MYMONEYTRACER(tracer); if (isEditMode()) { destroyEditWidgets(); this->setFocus(); } } -bool kMyMoneySplitTable::isEditMode() const +bool KMyMoneySplitTable::isEditMode() const { + Q_D(const KMyMoneySplitTable); // while the edit widgets exist we're in edit mode - return m_editAmount || m_editMemo || m_editCategory; + return d->m_editAmount || d->m_editMemo || d->m_editCategory; } -bool kMyMoneySplitTable::isEditSplitValid() const +bool KMyMoneySplitTable::isEditSplitValid() const { - return isEditMode() && !m_editCategory->selectedItem().isEmpty(); + Q_D(const KMyMoneySplitTable); + return isEditMode() && !d->m_editCategory->selectedItem().isEmpty(); } -void kMyMoneySplitTable::destroyEditWidgets() +void KMyMoneySplitTable::destroyEditWidgets() { MYMONEYTRACER(tracer); + Q_D(KMyMoneySplitTable); emit editFinished(); - disconnect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadEditWidgets())); + disconnect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, this, &KMyMoneySplitTable::slotLoadEditWidgets); - destroyEditWidget(m_currentRow, 0); - destroyEditWidget(m_currentRow, 1); - destroyEditWidget(m_currentRow, 2); - destroyEditWidget(m_currentRow + 1, 0); + destroyEditWidget(d->m_currentRow, 0); + destroyEditWidget(d->m_currentRow, 1); + destroyEditWidget(d->m_currentRow, 2); + destroyEditWidget(d->m_currentRow + 1, 0); } -void kMyMoneySplitTable::destroyEditWidget(int r, int c) +void KMyMoneySplitTable::destroyEditWidget(int r, int c) { if (QWidget* cw = cellWidget(r, c)) cw->hide(); removeCellWidget(r, c); } -KMyMoneyCategory* kMyMoneySplitTable::createEditWidgets(bool setFocus) +KMyMoneyCategory* KMyMoneySplitTable::createEditWidgets(bool setFocus) { MYMONEYTRACER(tracer); emit editStarted(); - QFont cellFont = KMyMoneyGlobalSettings::listCellFont(); - m_tabOrderWidgets.clear(); + Q_D(KMyMoneySplitTable); + auto cellFont = KMyMoneyGlobalSettings::listCellFont(); + d->m_tabOrderWidgets.clear(); // create the widgets - m_editAmount = new kMyMoneyEdit(0); - m_editAmount->setFont(cellFont); - m_editAmount->setResetButtonVisible(false); - m_editAmount->setPrecision(m_precision); + d->m_editAmount = new kMyMoneyEdit(0); + d->m_editAmount->setFont(cellFont); + d->m_editAmount->setResetButtonVisible(false); + d->m_editAmount->setPrecision(d->m_precision); - m_editCategory = new KMyMoneyCategory(); - m_editCategory->setPlaceholderText(i18n("Category")); - m_editCategory->setFont(cellFont); - connect(m_editCategory, SIGNAL(createItem(QString,QString&)), this, SIGNAL(createCategory(QString,QString&))); - connect(m_editCategory, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); + d->m_editCategory = new KMyMoneyCategory(); + d->m_editCategory->setPlaceholderText(i18n("Category")); + d->m_editCategory->setFont(cellFont); + connect(d->m_editCategory, SIGNAL(createItem(QString,QString&)), this, SIGNAL(createCategory(QString,QString&))); + connect(d->m_editCategory, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); - m_editMemo = new kMyMoneyLineEdit(0, false, Qt::AlignLeft | Qt::AlignVCenter); - m_editMemo->setPlaceholderText(i18n("Memo")); - m_editMemo->setFont(cellFont); + d->m_editMemo = new kMyMoneyLineEdit(0, false, Qt::AlignLeft | Qt::AlignVCenter); + d->m_editMemo->setPlaceholderText(i18n("Memo")); + d->m_editMemo->setFont(cellFont); // create buttons for the mouse users - m_registerButtonFrame = new QFrame(this); - m_registerButtonFrame->setContentsMargins(0, 0, 0, 0); - m_registerButtonFrame->setAutoFillBackground(true); + d->m_registerButtonFrame = new QFrame(this); + d->m_registerButtonFrame->setContentsMargins(0, 0, 0, 0); + d->m_registerButtonFrame->setAutoFillBackground(true); - QHBoxLayout* l = new QHBoxLayout(m_registerButtonFrame); + QHBoxLayout* l = new QHBoxLayout(d->m_registerButtonFrame); l->setContentsMargins(0, 0, 0, 0); l->setSpacing(0); - m_registerEnterButton = new QPushButton(QIcon::fromTheme(g_Icons[Icon::DialogOK]) - , QString(), m_registerButtonFrame); - m_registerCancelButton = new QPushButton(QIcon::fromTheme(g_Icons[Icon::DialogCancel]) - , QString(), m_registerButtonFrame); + d->m_registerEnterButton = new QPushButton(QIcon::fromTheme(g_Icons[Icon::DialogOK]) + , QString(), d->m_registerButtonFrame); + d->m_registerCancelButton = new QPushButton(QIcon::fromTheme(g_Icons[Icon::DialogCancel]) + , QString(), d->m_registerButtonFrame); - l->addWidget(m_registerEnterButton); - l->addWidget(m_registerCancelButton); + l->addWidget(d->m_registerEnterButton); + l->addWidget(d->m_registerCancelButton); l->addStretch(2); - connect(m_registerEnterButton, SIGNAL(clicked()), this, SLOT(slotEndEdit())); - connect(m_registerCancelButton, SIGNAL(clicked()), this, SLOT(slotCancelEdit())); + connect(d->m_registerEnterButton.data(), &QAbstractButton::clicked, this, &KMyMoneySplitTable::slotEndEdit); + connect(d->m_registerCancelButton.data(), &QAbstractButton::clicked, this, &KMyMoneySplitTable::slotCancelEdit); // setup tab order - addToTabOrder(m_editCategory); - addToTabOrder(m_editMemo); - addToTabOrder(m_editAmount); - addToTabOrder(m_registerEnterButton); - addToTabOrder(m_registerCancelButton); - - if (!m_split.accountId().isEmpty()) { - m_editCategory->setSelectedItem(m_split.accountId()); + addToTabOrder(d->m_editCategory); + addToTabOrder(d->m_editMemo); + addToTabOrder(d->m_editAmount); + addToTabOrder(d->m_registerEnterButton); + addToTabOrder(d->m_registerCancelButton); + + if (!d->m_split.accountId().isEmpty()) { + d->m_editCategory->setSelectedItem(d->m_split.accountId()); } else { // check if the transaction is balanced or not. If not, // assign the remainder to the amount. MyMoneyMoney diff; - QList list = m_transaction.splits(); + QList list = d->m_transaction.splits(); QList::ConstIterator it_s; for (it_s = list.constBegin(); it_s != list.constEnd(); ++it_s) { if (!(*it_s).accountId().isEmpty()) diff += (*it_s).value(); } - m_split.setValue(-diff); + d->m_split.setValue(-diff); } - m_editMemo->loadText(m_split.memo()); + d->m_editMemo->loadText(d->m_split.memo()); // don't allow automatically calculated values to be modified - if (m_split.value() == MyMoneyMoney::autoCalc) { - m_editAmount->setEnabled(false); - m_editAmount->loadText("will be calculated"); + if (d->m_split.value() == MyMoneyMoney::autoCalc) { + d->m_editAmount->setEnabled(false); + d->m_editAmount->loadText("will be calculated"); } else - m_editAmount->setValue(m_split.value()); + d->m_editAmount->setValue(d->m_split.value()); - setCellWidget(m_currentRow, 0, m_editCategory); - setCellWidget(m_currentRow, 1, m_editMemo); - setCellWidget(m_currentRow, 2, m_editAmount); - setCellWidget(m_currentRow + 1, 0, m_registerButtonFrame); + setCellWidget(d->m_currentRow, 0, d->m_editCategory); + setCellWidget(d->m_currentRow, 1, d->m_editMemo); + setCellWidget(d->m_currentRow, 2, d->m_editAmount); + setCellWidget(d->m_currentRow + 1, 0, d->m_registerButtonFrame); // load e.g. the category widget with the account list slotLoadEditWidgets(); - connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadEditWidgets())); + connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, this, &KMyMoneySplitTable::slotLoadEditWidgets); - foreach (QWidget* w, m_tabOrderWidgets) { + foreach (QWidget* w, d->m_tabOrderWidgets) { if (w) { w->installEventFilter(this); } } if (setFocus) { - m_editCategory->lineEdit()->setFocus(); - m_editCategory->lineEdit()->selectAll(); + d->m_editCategory->lineEdit()->setFocus(); + d->m_editCategory->lineEdit()->selectAll(); } // resize the rows so the added edit widgets would fit appropriately resizeRowsToContents(); - return m_editCategory; + return d->m_editCategory; } -void kMyMoneySplitTable::slotLoadEditWidgets() +void KMyMoneySplitTable::slotLoadEditWidgets() { + Q_D(KMyMoneySplitTable); // reload category widget - QString categoryId = m_editCategory->selectedItem(); + auto categoryId = d->m_editCategory->selectedItem(); AccountSet aSet; aSet.addAccountGroup(eMyMoney::Account::Asset); aSet.addAccountGroup(eMyMoney::Account::Liability); aSet.addAccountGroup(eMyMoney::Account::Income); aSet.addAccountGroup(eMyMoney::Account::Expense); if (KMyMoneyGlobalSettings::expertMode()) aSet.addAccountGroup(eMyMoney::Account::Equity); // remove the accounts with invalid types at this point aSet.removeAccountType(eMyMoney::Account::CertificateDep); aSet.removeAccountType(eMyMoney::Account::Investment); aSet.removeAccountType(eMyMoney::Account::Stock); aSet.removeAccountType(eMyMoney::Account::MoneyMarket); - aSet.load(m_editCategory->selector()); + aSet.load(d->m_editCategory->selector()); // if an account is specified then remove it from the widget so that the user // cannot create a transfer with from and to account being the same account - if (!m_account.id().isEmpty()) - m_editCategory->selector()->removeItem(m_account.id()); + if (!d->m_account.id().isEmpty()) + d->m_editCategory->selector()->removeItem(d->m_account.id()); if (!categoryId.isEmpty()) - m_editCategory->setSelectedItem(categoryId); + d->m_editCategory->setSelectedItem(categoryId); } -void kMyMoneySplitTable::addToTabOrder(QWidget* w) +void KMyMoneySplitTable::addToTabOrder(QWidget* w) { + Q_D(KMyMoneySplitTable); if (w) { while (w->focusProxy()) w = w->focusProxy(); - m_tabOrderWidgets.append(w); + d->m_tabOrderWidgets.append(w); } } -bool kMyMoneySplitTable::focusNextPrevChild(bool next) +bool KMyMoneySplitTable::focusNextPrevChild(bool next) { MYMONEYTRACER(tracer); - bool rc = false; + Q_D(KMyMoneySplitTable); + auto rc = false; if (isEditMode()) { QWidget *w = 0; w = qApp->focusWidget(); - int currentWidgetIndex = m_tabOrderWidgets.indexOf(w); + int currentWidgetIndex = d->m_tabOrderWidgets.indexOf(w); while (w && currentWidgetIndex == -1) { // qDebug("'%s' not in list, use parent", w->className()); w = w->parentWidget(); - currentWidgetIndex = m_tabOrderWidgets.indexOf(w); + currentWidgetIndex = d->m_tabOrderWidgets.indexOf(w); } if (currentWidgetIndex != -1) { // if(w) qDebug("tab order is at '%s'", w->className()); currentWidgetIndex += next ? 1 : -1; if (currentWidgetIndex < 0) - currentWidgetIndex = m_tabOrderWidgets.size() - 1; - else if (currentWidgetIndex >= m_tabOrderWidgets.size()) + currentWidgetIndex = d->m_tabOrderWidgets.size() - 1; + else if (currentWidgetIndex >= d->m_tabOrderWidgets.size()) currentWidgetIndex = 0; - w = m_tabOrderWidgets[currentWidgetIndex]; + w = d->m_tabOrderWidgets[currentWidgetIndex]; if (((w->focusPolicy() & Qt::TabFocus) == Qt::TabFocus) && w->isVisible() && w->isEnabled()) { // qDebug("Selecting '%s' as focus", w->className()); w->setFocus(); rc = true; } } } else rc = QTableWidget::focusNextPrevChild(next); return rc; } diff --git a/kmymoney/dialogs/kmymoneysplittable.h b/kmymoney/dialogs/kmymoneysplittable.h index 2421bfd3c..9b6ebcd0e 100644 --- a/kmymoney/dialogs/kmymoneysplittable.h +++ b/kmymoney/dialogs/kmymoneysplittable.h @@ -1,268 +1,209 @@ /*************************************************************************** kmymoneysplittable.h - description ------------------- begin : Thu Jan 10 2002 copyright : (C) 2000-2002 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KMYMONEYSPLITTABLE_H #define KMYMONEYSPLITTABLE_H // ---------------------------------------------------------------------------- // QT Includes #include -#include -#include // ---------------------------------------------------------------------------- // KDE Includes -class QMenu; -class QPushButton; -class QFrame; // ---------------------------------------------------------------------------- // Project Includes -#include "mymoneysplit.h" -#include "mymoneytransaction.h" -#include "mymoneyaccount.h" - class KMyMoneyCategory; -class kMyMoneyLineEdit; -class kMyMoneyEdit; +class MyMoneyMoney; +class MyMoneySplit; +class MyMoneyTransaction; +class MyMoneyAccount; + +template class QMap; /** * @author Thomas Baumgart */ -class kMyMoneySplitTable : public QTableWidget +class KMyMoneySplitTablePrivate; +class KMyMoneySplitTable : public QTableWidget { Q_OBJECT + Q_DISABLE_COPY(KMyMoneySplitTable) public: - explicit kMyMoneySplitTable(QWidget *parent = 0); - virtual ~kMyMoneySplitTable(); + explicit KMyMoneySplitTable(QWidget *parent = nullptr); + ~KMyMoneySplitTable(); /** * This method is used to load the widget with the information about * the transaction @p t. The split referencing the account @p acc is * not shown in the widget. * * @param t reference to transaction to be shown/modified * @param s reference to split that is to be hidden * @param acc reference to account */ void setTransaction(const MyMoneyTransaction& t, const MyMoneySplit& s, const MyMoneyAccount& acc); /** * This method is used to retrieve the transaction from the widget. */ - const MyMoneyTransaction& transaction() const { - return m_transaction; - } + MyMoneyTransaction transaction() const; /** * Returns a list of MyMoneySplit objects. It contains all but the one * referencing the account passed in setTransaction(). * * @param t reference to transaction * @return list of splits */ - const QList getSplits(const MyMoneyTransaction& t) const; + QList getSplits(const MyMoneyTransaction& t) const; void setup(const QMap& priceInfo, int precision); int currentRow() const; protected: - void mousePressEvent(QMouseEvent* e); - void mouseReleaseEvent(QMouseEvent* e); - void mouseDoubleClickEvent(QMouseEvent* e); - bool eventFilter(QObject *o, QEvent *e); + void mousePressEvent(QMouseEvent* e) override; + void mouseReleaseEvent(QMouseEvent* e) override; + void mouseDoubleClickEvent(QMouseEvent* e) override; + bool eventFilter(QObject *o, QEvent *e) override; - void resizeEvent(QResizeEvent*); + void resizeEvent(QResizeEvent*) override; KMyMoneyCategory* createEditWidgets(bool setFocus); void destroyEditWidgets(); void destroyEditWidget(int r, int c); /** * This method handles the focus of the keyboard. When in edit mode * (m_editCategory widget is visible) the keyboard focus is handled * according to the widgets that are referenced in m_tabOrderWidgets. * If not in edit mode, the base class functionality is provided. * * @param next true if forward-tab, false if backward-tab was * pressed by the user */ - virtual bool focusNextPrevChild(bool next); + bool focusNextPrevChild(bool next) override; void addToTabOrder(QWidget* w); void updateTransactionTableSize(); /** * This method returns the current state of the inline editing mode * * @return true if inline edit mode is on, false otherwise */ bool isEditMode() const; /** * This method returns true if the currently edited split is valid * and can be entered. * * @return true if the split can be entered, false otherwise */ bool isEditSplitValid() const; void endEdit(bool keyboardDriven, bool setFocusToNextRow = true); public slots: /** No descriptions */ virtual void setRowCount(int r); void selectRow(int row); KMyMoneyCategory* slotStartEdit(); void slotEndEdit(); void slotEndEditKeyboard(); void slotDeleteSplit(); void slotCancelEdit(); void slotDuplicateSplit(); protected slots: /// move the focus to the selected @p row. - void slotSetFocus(const QModelIndex& index, int button = Qt::LeftButton); + void slotSetFocus(const QModelIndex& index); + void slotSetFocus(const QModelIndex& index, int button); /** * Calling this slot refills the widget with the data * passed in the argument @p t. * * @param t reference to transaction data */ void slotUpdateData(const MyMoneyTransaction& t); void slotLoadEditWidgets(); signals: /** * This signal is emitted whenever the widget goes into edit mode. */ void editStarted(); /** * This signal is emitted whenever the widget ends edit mode. */ void editFinished(); /** * This signal is emitted whenever the return key is pressed * and the widget is not in edit mode. */ void escapePressed(); /** * This signal is emitted whenever the return key is pressed * and the widget is not in edit mode. */ void returnPressed(); /** * This signal is emitted whenever the transaction data has been changed * * @param t modified transaction data */ void transactionChanged(const MyMoneyTransaction& t); /** * This signal is sent out, when a new category needs to be created * @sa KMyMoneyCombo::createItem() * * @param txt The name of the category to be created * @param id A connected slot should store the id of the created object in this variable */ void createCategory(const QString& txt, QString& id); /** * Signal is emitted, if any of the widgets enters (@a state equals @a true) * or leaves (@a state equals @a false) object creation mode. * * @param state Enter (@a true) or leave (@a false) object creation */ void objectCreation(bool state); private: - /// the currently selected row (will be printed as selected) - int m_currentRow; - - /// the number of rows filled with data - int m_maxRows; - - MyMoneyTransaction m_transaction; - MyMoneyAccount m_account; - MyMoneySplit m_split; - MyMoneySplit m_hiddenSplit; - - /** - * This member keeps the precision for the values - */ - int m_precision; - - /** - * This member keeps a pointer to the context menu - */ - QMenu* m_contextMenu; - - /// keeps the QAction of the delete entry in the context menu - QAction* m_contextMenuDelete; - - /// keeps the QAction of the duplicate entry in the context menu - QAction* m_contextMenuDuplicate; - - /** - * This member contains a pointer to the input widget for the category. - * The widget will be created and destroyed dynamically in createInputWidgets() - * and destroyInputWidgets(). - */ - QPointer m_editCategory; - - /** - * This member contains a pointer to the input widget for the memo. - * The widget will be created and destroyed dynamically in createInputWidgets() - * and destroyInputWidgets(). - */ - QPointer m_editMemo; - - /** - * This member contains a pointer to the input widget for the amount. - * The widget will be created and destroyed dynamically in createInputWidgets() - * and destroyInputWidgets(). - */ - QPointer m_editAmount; - - /** - * This member keeps the tab order for the above widgets - */ - QWidgetList m_tabOrderWidgets; - - QPointer m_registerButtonFrame; - QPointer m_registerEnterButton; - QPointer m_registerCancelButton; - - QMap m_priceInfo; + KMyMoneySplitTablePrivate * const d_ptr; + Q_DECLARE_PRIVATE(KMyMoneySplitTable) }; #endif diff --git a/kmymoney/dialogs/knewaccountdlg.cpp b/kmymoney/dialogs/knewaccountdlg.cpp index cd0771a9b..84182dbd1 100644 --- a/kmymoney/dialogs/knewaccountdlg.cpp +++ b/kmymoney/dialogs/knewaccountdlg.cpp @@ -1,919 +1,916 @@ /*************************************************************************** knewaccountdlg.cpp ------------------- copyright : (C) 2000 by Michael Edwardes 2004 by Thomas Baumgart (C) 2017 by Ł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. * * * ***************************************************************************/ #include "knewaccountdlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Headers #include #include -#include #include #include // ---------------------------------------------------------------------------- // Project Includes #include "ui_knewaccountdlg.h" #include "kmymoneyedit.h" #include "kmymoneydateinput.h" #include #include "mymoneyfile.h" +#include "mymoneyinstitution.h" #include "mymoneyaccount.h" #include "kmymoneyglobalsettings.h" #include "kmymoneycurrencyselector.h" #include "knewbankdlg.h" -#include "kmymoneyutils.h" #include "models.h" #include "accountsmodel.h" #include "hierarchyfilterproxymodel.h" -namespace Ui { class KNewAccountDlg; } - using namespace eMyMoney; class KNewAccountDlgPrivate { Q_DISABLE_COPY(KNewAccountDlgPrivate) Q_DECLARE_PUBLIC(KNewAccountDlg) public: KNewAccountDlgPrivate(KNewAccountDlg *qq) : q_ptr(qq), ui(new Ui::KNewAccountDlg) { } ~KNewAccountDlgPrivate() { delete ui; } void init() { Q_Q(KNewAccountDlg); ui->setupUi(q); auto file = MyMoneyFile::instance(); // initialize the m_parentAccount member QVector filterAccountGroup {m_account.accountGroup()}; switch (m_account.accountGroup()) { case Account::Asset: m_parentAccount = file->asset(); break; case Account::Liability: m_parentAccount = file->liability(); break; case Account::Income: m_parentAccount = file->income(); break; case Account::Expense: m_parentAccount = file->expense(); break; case Account::Equity: m_parentAccount = file->equity(); break; default: qDebug("Seems we have an account that hasn't been mapped to the top five"); if (m_categoryEditor) { m_parentAccount = file->income(); filterAccountGroup[0] = Account::Income; } else { m_parentAccount = file->asset(); filterAccountGroup[0] = Account::Asset; } } ui->m_amountGroup->setId(ui->m_grossAmount, 0); ui->m_amountGroup->setId(ui->m_netAmount, 1); // the proxy filter model m_filterProxyModel = new HierarchyFilterProxyModel(q); m_filterProxyModel->setHideClosedAccounts(true); m_filterProxyModel->setHideEquityAccounts(!KMyMoneyGlobalSettings::expertMode()); m_filterProxyModel->addAccountGroup(filterAccountGroup); m_filterProxyModel->setCurrentAccountId(m_account.id()); auto const model = Models::instance()->accountsModel(); m_filterProxyModel->setSourceModel(model); m_filterProxyModel->setSourceColumns(model->getColumns()); m_filterProxyModel->setDynamicSortFilter(true); ui->m_parentAccounts->setModel(m_filterProxyModel); ui->m_parentAccounts->sortByColumn((int)eAccountsModel::Column::Account, Qt::AscendingOrder); ui->m_subAccountLabel->setText(i18n("Is a sub account")); ui->accountNameEdit->setText(m_account.name()); ui->descriptionEdit->setText(m_account.description()); ui->typeCombo->setEnabled(true); // load the price mode combo ui->m_priceMode->insertItem(i18nc("default price mode", "(default)"), 0); ui->m_priceMode->insertItem(i18n("Price per share"), 1); ui->m_priceMode->insertItem(i18n("Total for all shares"), 2); int priceMode = 0; if (m_account.accountType() == Account::Investment) { ui->m_priceMode->setEnabled(true); if (!m_account.value("priceMode").isEmpty()) priceMode = m_account.value("priceMode").toInt(); } ui->m_priceMode->setCurrentItem(priceMode); bool haveMinBalance = false; bool haveMaxCredit = false; if (!m_account.openingDate().isValid()) { m_account.setOpeningDate(KMyMoneyGlobalSettings::firstFiscalDate()); } ui->m_openingDateEdit->setDate(m_account.openingDate()); handleOpeningBalanceCheckbox(m_account.currencyId()); if (m_categoryEditor) { // get rid of the tabs that are not used for categories int tab = ui->m_tab->indexOf(ui->m_institutionTab); if (tab != -1) ui->m_tab->removeTab(tab); tab = ui->m_tab->indexOf(ui->m_limitsTab); if (tab != -1) ui->m_tab->removeTab(tab); //m_qlistviewParentAccounts->setEnabled(true); ui->accountNoEdit->setEnabled(false); ui->m_institutionBox->hide(); ui->m_qcheckboxNoVat->hide(); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Income), (int)Account::Income); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Expense), (int)Account::Expense); // Hardcoded but acceptable - if above we set the default to income do the same here switch (m_account.accountType()) { case Account::Expense: ui->typeCombo->setCurrentItem(MyMoneyAccount::accountTypeToString(Account::Expense), false); break; case Account::Income: default: ui->typeCombo->setCurrentItem(MyMoneyAccount::accountTypeToString(Account::Income), false); break; } ui->m_currency->setEnabled(true); if (m_isEditing) { ui->typeCombo->setEnabled(false); ui->m_currency->setDisabled(MyMoneyFile::instance()->isReferenced(m_account)); } ui->m_qcheckboxPreferred->hide(); ui->m_qcheckboxTax->setChecked(m_account.value("Tax").toLower() == "yes"); ui->m_costCenterRequiredCheckBox->setChecked(m_account.isCostCenterRequired()); loadVatAccounts(); } else { // get rid of the tabs that are not used for accounts int taxtab = ui->m_tab->indexOf(ui->m_taxTab); if (taxtab != -1) { ui->m_vatCategory->setText(i18n("VAT account")); ui->m_qcheckboxTax->setChecked(m_account.value("Tax") == "Yes"); loadVatAccounts(); } else { ui->m_tab->removeTab(taxtab); } ui->m_costCenterRequiredCheckBox->hide(); switch (m_account.accountType()) { case Account::Savings: case Account::Cash: haveMinBalance = true; break; case Account::Checkings: haveMinBalance = true; haveMaxCredit = true; break; case Account::CreditCard: haveMaxCredit = true; break; default: // no limit available, so we might get rid of the tab int tab = ui->m_tab->indexOf(ui->m_limitsTab); if (tab != -1) ui->m_tab->removeTab(tab); // don't try to hide the widgets we just wiped // in the next step haveMaxCredit = haveMinBalance = true; break; } if (!haveMaxCredit) { ui->m_maxCreditLabel->setEnabled(false); ui->m_maxCreditLabel->hide(); ui->m_maxCreditEarlyEdit->hide(); ui->m_maxCreditAbsoluteEdit->hide(); } if (!haveMinBalance) { ui->m_minBalanceLabel->setEnabled(false); ui->m_minBalanceLabel->hide(); ui->m_minBalanceEarlyEdit->hide(); ui->m_minBalanceAbsoluteEdit->hide(); } QString typeString = MyMoneyAccount::accountTypeToString(m_account.accountType()); if (m_isEditing) { if (m_account.isLiquidAsset()) { ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Checkings), (int)Account::Checkings); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Savings), (int)Account::Savings); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Cash), (int)Account::Cash); } else { ui->typeCombo->addItem(typeString, (int)m_account.accountType()); // Once created, accounts of other account types are not // allowed to be changed. ui->typeCombo->setEnabled(false); } // Once created, a currency cannot be changed if it is referenced. ui->m_currency->setDisabled(MyMoneyFile::instance()->isReferenced(m_account)); } else { ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Checkings), (int)Account::Checkings); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Savings), (int)Account::Savings); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Cash), (int)Account::Cash); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::CreditCard), (int)Account::CreditCard); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Loan), (int)Account::Loan); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Investment), (int)Account::Investment); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Asset), (int)Account::Asset); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Liability), (int)Account::Liability); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Stock), (int)Account::Stock); /* ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::CertificateDep), (int)Account::CertificateDep); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::MoneyMarket), (int)Account::MoneyMarket); ui->typeCombo->addItem(MyMoneyAccount::accountTypeToString(Account::Currency), (int)Account::Currency); */ // Do not create account types that are not supported // by the current engine. if (m_account.accountType() == Account::Unknown || m_account.accountType() == Account::CertificateDep || m_account.accountType() == Account::MoneyMarket || m_account.accountType() == Account::Currency) typeString = MyMoneyAccount::accountTypeToString(Account::Checkings); } ui->typeCombo->setCurrentItem(typeString, false); if (m_account.isInvest()) ui->m_institutionBox->hide(); ui->accountNoEdit->setText(m_account.number()); ui->m_qcheckboxPreferred->setChecked(m_account.value("PreferredAccount") == "Yes"); ui->m_qcheckboxNoVat->setChecked(m_account.value("NoVat") == "Yes"); loadKVP("iban", ui->ibanEdit); loadKVP("minBalanceAbsolute", ui->m_minBalanceAbsoluteEdit); loadKVP("minBalanceEarly", ui->m_minBalanceEarlyEdit); loadKVP("maxCreditAbsolute", ui->m_maxCreditAbsoluteEdit); loadKVP("maxCreditEarly", ui->m_maxCreditEarlyEdit); // reverse the sign for display purposes if (!ui->m_maxCreditAbsoluteEdit->lineedit()->text().isEmpty()) ui->m_maxCreditAbsoluteEdit->setValue(ui->m_maxCreditAbsoluteEdit->value()*MyMoneyMoney::MINUS_ONE); if (!ui->m_maxCreditEarlyEdit->lineedit()->text().isEmpty()) ui->m_maxCreditEarlyEdit->setValue(ui->m_maxCreditEarlyEdit->value()*MyMoneyMoney::MINUS_ONE); loadKVP("lastNumberUsed", ui->m_lastCheckNumberUsed); if (m_account.isInvest()) { ui->typeCombo->setEnabled(false); ui->m_qcheckboxPreferred->hide(); ui->m_currencyText->hide(); ui->m_currency->hide(); } else { // use the old field and override a possible new value if (!MyMoneyMoney(m_account.value("minimumBalance")).isZero()) { ui->m_minBalanceAbsoluteEdit->setValue(MyMoneyMoney(m_account.value("minimumBalance"))); } } // ui->m_qcheckboxTax->hide(); TODO should only be visible for VAT category/account } ui->m_currency->setSecurity(file->currency(m_account.currencyId())); // Load the institutions // then the accounts QString institutionName; try { if (m_isEditing && !m_account.institutionId().isEmpty()) institutionName = file->institution(m_account.institutionId()).name(); else institutionName.clear(); } catch (const MyMoneyException &e) { qDebug("exception in init for account dialog: %s", qPrintable(e.what())); } if (m_account.isInvest()) ui->m_parentAccounts->setEnabled(false); if (!m_categoryEditor) q->slotLoadInstitutions(institutionName); ui->accountNameEdit->setFocus(); q->connect(ui->buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject); q->connect(ui->buttonBox, &QDialogButtonBox::accepted, q, &KNewAccountDlg::okClicked); q->connect(ui->m_parentAccounts->selectionModel(), &QItemSelectionModel::selectionChanged, q, &KNewAccountDlg::slotSelectionChanged); q->connect(ui->m_qbuttonNew, &QAbstractButton::clicked, q, &KNewAccountDlg::slotNewClicked); q->connect(ui->typeCombo, static_cast(&QComboBox::currentIndexChanged), q, &KNewAccountDlg::slotAccountTypeChanged); q->connect(ui->accountNameEdit, &QLineEdit::textChanged, q, &KNewAccountDlg::slotCheckFinished); q->connect(ui->m_vatCategory, &QAbstractButton::toggled, q, &KNewAccountDlg::slotVatChanged); q->connect(ui->m_vatAssignment, &QAbstractButton::toggled, q, &KNewAccountDlg::slotVatAssignmentChanged); q->connect(ui->m_vatCategory, &QAbstractButton::toggled, q, &KNewAccountDlg::slotCheckFinished); q->connect(ui->m_vatAssignment, &QAbstractButton::toggled, q, &KNewAccountDlg::slotCheckFinished); q->connect(ui->m_vatRate, &kMyMoneyEdit::textChanged, q, &KNewAccountDlg::slotCheckFinished); q->connect(ui->m_vatAccount, &KMyMoneySelector::stateChanged, q, &KNewAccountDlg::slotCheckFinished); q->connect(ui->m_currency, static_cast(&QComboBox::activated), q, &KNewAccountDlg::slotCheckCurrency); q->connect(ui->m_minBalanceEarlyEdit, &kMyMoneyEdit::valueChanged, q, &KNewAccountDlg::slotAdjustMinBalanceAbsoluteEdit); q->connect(ui->m_minBalanceAbsoluteEdit, &kMyMoneyEdit::valueChanged, q, &KNewAccountDlg::slotAdjustMinBalanceEarlyEdit); q->connect(ui->m_maxCreditEarlyEdit, &kMyMoneyEdit::valueChanged, q, &KNewAccountDlg::slotAdjustMaxCreditAbsoluteEdit); q->connect(ui->m_maxCreditAbsoluteEdit, &kMyMoneyEdit::valueChanged, q, &KNewAccountDlg::slotAdjustMaxCreditEarlyEdit); q->connect(ui->m_qcomboboxInstitutions, static_cast(&QComboBox::activated), q, &KNewAccountDlg::slotLoadInstitutions); auto parentIndex = m_filterProxyModel->getSelectedParentAccountIndex(); ui->m_parentAccounts->expand(parentIndex); ui->m_parentAccounts->selectionModel()->select(parentIndex, QItemSelectionModel::SelectCurrent); ui->m_parentAccounts->scrollTo(parentIndex, QAbstractItemView::PositionAtTop); ui->m_vatCategory->setChecked(false); ui->m_vatAssignment->setChecked(false); // make sure our account does not have an id and no parent assigned // and certainly no children in case we create a new account if (!m_isEditing) { m_account.clearId(); m_account.setParentAccountId(QString()); m_account.removeAccountIds(); } else { if (!m_account.value("VatRate").isEmpty()) { ui->m_vatCategory->setChecked(true); ui->m_vatRate->setValue(MyMoneyMoney(m_account.value("VatRate"))*MyMoneyMoney(100, 1)); } else { if (!m_account.value("VatAccount").isEmpty()) { QString accId = m_account.value("VatAccount").toLatin1(); try { // make sure account exists MyMoneyFile::instance()->account(accId); ui->m_vatAssignment->setChecked(true); ui->m_vatAccount->setSelected(accId); ui->m_grossAmount->setChecked(true); if (m_account.value("VatAmount") == "Net") ui->m_netAmount->setChecked(true); } catch (const MyMoneyException &) { } } } } q->slotVatChanged(ui->m_vatCategory->isChecked()); q->slotVatAssignmentChanged(ui->m_vatAssignment->isChecked()); q->slotCheckFinished(); auto requiredFields = new kMandatoryFieldGroup(q); requiredFields->setOkButton(ui->buttonBox->button(QDialogButtonBox::Ok)); // button to be enabled when all fields present requiredFields->add(ui->accountNameEdit); } void loadKVP(const QString& key, kMyMoneyEdit* widget) { if (!widget) return; if (m_account.value(key).isEmpty()) { widget->clearText(); } else { widget->setValue(MyMoneyMoney(m_account.value(key))); } } void loadKVP(const QString& key, KLineEdit* widget) { if (!widget) return; widget->setText(m_account.value(key)); } void storeKVP(const QString& key, const QString& text, const QString& value) { if (text.isEmpty()) m_account.deletePair(key); else m_account.setValue(key, value); } void storeKVP(const QString& key, QCheckBox* widget) { if (widget) { if(widget->isChecked()) { m_account.setValue(key, "Yes");; } else { m_account.deletePair(key); } } } void storeKVP(const QString& key, kMyMoneyEdit* widget) { storeKVP(key, widget->lineedit()->text(), widget->text()); } void storeKVP(const QString& key, KLineEdit* widget) { storeKVP(key, widget->text(), widget->text()); } void loadVatAccounts() { QList list; MyMoneyFile::instance()->accountList(list); QList::Iterator it; QStringList loadListExpense; QStringList loadListIncome; QStringList loadListAsset; QStringList loadListLiability; for (it = list.begin(); it != list.end(); ++it) { if (!(*it).value("VatRate").isEmpty()) { if ((*it).accountType() == Account::Expense) loadListExpense += (*it).id(); else if ((*it).accountType() == Account::Income) loadListIncome += (*it).id(); else if ((*it).accountType() == Account::Asset) loadListAsset += (*it).id(); else if ((*it).accountType() == Account::Liability) loadListLiability += (*it).id(); } } AccountSet vatSet; if (!loadListAsset.isEmpty()) vatSet.load(ui->m_vatAccount, i18n("Asset"), loadListAsset, true); if (!loadListLiability.isEmpty()) vatSet.load(ui->m_vatAccount, i18n("Liability"), loadListLiability, false); if (!loadListIncome.isEmpty()) vatSet.load(ui->m_vatAccount, i18n("Income"), loadListIncome, false); if (!loadListExpense.isEmpty()) vatSet.load(ui->m_vatAccount, i18n("Expense"), loadListExpense, false); } void adjustEditWidgets(kMyMoneyEdit* dst, kMyMoneyEdit* src, char mode, int corr) { MyMoneyMoney factor(corr, 1); if (m_account.accountGroup() == Account::Asset) factor = -factor; switch (mode) { case '<': if (src->value()*factor < dst->value()*factor) dst->setValue(src->value()); break; case '>': if (src->value()*factor > dst->value()*factor) dst->setValue(src->value()); break; } } void handleOpeningBalanceCheckbox(const QString ¤cyId) { if (m_account.accountType() == Account::Equity) { // check if there is another opening balance account with the same currency bool isOtherOpenBalancingAccount = false; QList list; MyMoneyFile::instance()->accountList(list); QList::Iterator it; for (it = list.begin(); it != list.end(); ++it) { if (it->id() == m_account.id() || currencyId != it->currencyId() || it->accountType() != Account::Equity) continue; if (it->value("OpeningBalanceAccount") == "Yes") { isOtherOpenBalancingAccount = true; break; } } if (!isOtherOpenBalancingAccount) { bool isOpenBalancingAccount = m_account.value("OpeningBalanceAccount") == "Yes"; ui->m_qcheckboxOpeningBalance->setChecked(isOpenBalancingAccount); if (isOpenBalancingAccount) { // let only allow state change if no transactions are assigned to this account bool hasTransactions = MyMoneyFile::instance()->transactionCount(m_account.id()) != 0; ui->m_qcheckboxOpeningBalance->setEnabled(!hasTransactions); if (hasTransactions) ui->m_qcheckboxOpeningBalance->setToolTip(i18n("Option has been disabled because there are transactions assigned to this account")); } } else { ui->m_qcheckboxOpeningBalance->setChecked(false); ui->m_qcheckboxOpeningBalance->setEnabled(false); ui->m_qcheckboxOpeningBalance->setToolTip(i18n("Option has been disabled because there is another account flagged to be an opening balance account for this currency")); } } else { ui->m_qcheckboxOpeningBalance->setVisible(false); } } KNewAccountDlg *q_ptr; Ui::KNewAccountDlg *ui; MyMoneyAccount m_account; MyMoneyAccount m_parentAccount; HierarchyFilterProxyModel *m_filterProxyModel; bool m_categoryEditor; bool m_isEditing; }; KNewAccountDlg::KNewAccountDlg(const MyMoneyAccount& account, bool isEditing, bool categoryEditor, QWidget *parent, const QString& title) : QDialog(parent), d_ptr(new KNewAccountDlgPrivate(this)) { Q_D(KNewAccountDlg); d->m_account = account; d->m_categoryEditor = categoryEditor; d->m_isEditing = isEditing; if (!title.isEmpty()) setWindowTitle(title); d->init(); } MyMoneyMoney KNewAccountDlg::openingBalance() const { Q_D(const KNewAccountDlg); return d->ui->m_openingBalanceEdit->value(); } void KNewAccountDlg::setOpeningBalance(const MyMoneyMoney& balance) { Q_D(KNewAccountDlg); d->ui->m_openingBalanceEdit->setValue(balance); } void KNewAccountDlg::setOpeningBalanceShown(bool shown) { Q_D(KNewAccountDlg); d->ui->m_openingBalanceLabel->setVisible(shown); d->ui->m_openingBalanceEdit->setVisible(shown); } void KNewAccountDlg::setOpeningDateShown(bool shown) { Q_D(KNewAccountDlg); d->ui->m_openingDateLabel->setVisible(shown); d->ui->m_openingDateEdit->setVisible(shown); } void KNewAccountDlg::okClicked() { Q_D(KNewAccountDlg); - MyMoneyFile* file = MyMoneyFile::instance(); + auto file = MyMoneyFile::instance(); QString accountNameText = d->ui->accountNameEdit->text(); if (accountNameText.isEmpty()) { KMessageBox::error(this, i18n("You have not specified a name.\nPlease fill in this field.")); d->ui->accountNameEdit->setFocus(); return; } MyMoneyAccount parent = parentAccount(); if (parent.name().length() == 0) { KMessageBox::error(this, i18n("Please select a parent account.")); return; } if (!d->m_categoryEditor) { QString institutionNameText = d->ui->m_qcomboboxInstitutions->currentText(); if (institutionNameText != i18n("(No Institution)")) { try { auto file = MyMoneyFile::instance(); QList list = file->institutionList(); QList::ConstIterator institutionIterator; for (institutionIterator = list.constBegin(); institutionIterator != list.constEnd(); ++institutionIterator) { if ((*institutionIterator).name() == institutionNameText) d->m_account.setInstitutionId((*institutionIterator).id()); } } catch (const MyMoneyException &e) { qDebug("Exception in account institution set: %s", qPrintable(e.what())); } } else { d->m_account.setInstitutionId(QString()); } } d->m_account.setName(accountNameText); d->m_account.setNumber(d->ui->accountNoEdit->text()); d->storeKVP("iban", d->ui->ibanEdit); d->storeKVP("minBalanceAbsolute", d->ui->m_minBalanceAbsoluteEdit); d->storeKVP("minBalanceEarly", d->ui->m_minBalanceEarlyEdit); // the figures for credit line with reversed sign if (!d->ui->m_maxCreditAbsoluteEdit->lineedit()->text().isEmpty()) d->ui->m_maxCreditAbsoluteEdit->setValue(d->ui->m_maxCreditAbsoluteEdit->value()*MyMoneyMoney::MINUS_ONE); if (!d->ui->m_maxCreditEarlyEdit->lineedit()->text().isEmpty()) d->ui->m_maxCreditEarlyEdit->setValue(d->ui->m_maxCreditEarlyEdit->value()*MyMoneyMoney::MINUS_ONE); d->storeKVP("maxCreditAbsolute", d->ui->m_maxCreditAbsoluteEdit); d->storeKVP("maxCreditEarly", d->ui->m_maxCreditEarlyEdit); if (!d->ui->m_maxCreditAbsoluteEdit->lineedit()->text().isEmpty()) d->ui->m_maxCreditAbsoluteEdit->setValue(d->ui->m_maxCreditAbsoluteEdit->value()*MyMoneyMoney::MINUS_ONE); if (!d->ui->m_maxCreditEarlyEdit->lineedit()->text().isEmpty()) d->ui->m_maxCreditEarlyEdit->setValue(d->ui->m_maxCreditEarlyEdit->value()*MyMoneyMoney::MINUS_ONE); d->storeKVP("lastNumberUsed", d->ui->m_lastCheckNumberUsed); // delete a previous version of the minimumbalance information d->storeKVP("minimumBalance", QString(), QString()); Account acctype; if (!d->m_categoryEditor) { acctype = static_cast(d->ui->typeCombo->currentData().toInt()); // If it's a loan, check if the parent is asset or liability. In // case of asset, we change the account type to be AssetLoan if (acctype == Account::Loan && parent.accountGroup() == Account::Asset) acctype = Account::AssetLoan; } else { acctype = parent.accountGroup(); QString newName; if (!MyMoneyFile::instance()->isStandardAccount(parent.id())) { newName = MyMoneyFile::instance()->accountToCategory(parent.id()) + MyMoneyFile::AccountSeperator; } newName += accountNameText; if (!file->categoryToAccount(newName, acctype).isEmpty() && (file->categoryToAccount(newName, acctype) != d->m_account.id())) { KMessageBox::error(this, QString("") + i18n("A category named %1 already exists. You cannot create a second category with the same name.", newName) + QString("")); return; } } d->m_account.setAccountType(acctype); d->m_account.setDescription(d->ui->descriptionEdit->toPlainText()); d->m_account.setOpeningDate(d->ui->m_openingDateEdit->date()); if (!d->m_categoryEditor) { d->m_account.setCurrencyId(d->ui->m_currency->security().id()); d->storeKVP("PreferredAccount", d->ui->m_qcheckboxPreferred); d->storeKVP("NoVat", d->ui->m_qcheckboxNoVat); if (d->ui->m_minBalanceAbsoluteEdit->isVisible()) { d->m_account.setValue("minimumBalance", d->ui->m_minBalanceAbsoluteEdit->value().toString()); } } else { if (KMyMoneyGlobalSettings::hideUnusedCategory() && !d->m_isEditing) { KMessageBox::information(this, i18n("You have selected to suppress the display of unused categories in the KMyMoney configuration dialog. The category you just created will therefore only be shown if it is used. Otherwise, it will be hidden in the accounts/categories view."), i18n("Hidden categories"), "NewHiddenCategory"); } d->m_account.setCostCenterRequired(d->ui->m_costCenterRequiredCheckBox->isChecked()); } d->storeKVP("Tax", d->ui->m_qcheckboxTax); if (d->ui->m_qcheckboxOpeningBalance->isChecked()) d->m_account.setValue("OpeningBalanceAccount", "Yes"); else d->m_account.deletePair("OpeningBalanceAccount"); d->m_account.deletePair("VatAccount"); d->m_account.deletePair("VatAmount"); d->m_account.deletePair("VatRate"); if (d->ui->m_vatCategory->isChecked()) { d->m_account.setValue("VatRate", (d->ui->m_vatRate->value().abs() / MyMoneyMoney(100, 1)).toString()); } else { if (d->ui->m_vatAssignment->isChecked() && !d->ui->m_vatAccount->selectedItems().isEmpty()) { d->m_account.setValue("VatAccount", d->ui->m_vatAccount->selectedItems().first()); if (d->ui->m_netAmount->isChecked()) d->m_account.setValue("VatAmount", "Net"); } } accept(); } MyMoneyAccount KNewAccountDlg::account() { Q_D(KNewAccountDlg); // assign the right currency to the account d->m_account.setCurrencyId(d->ui->m_currency->security().id()); // and the price mode switch (d->ui->m_priceMode->currentItem()) { case 0: d->m_account.deletePair("priceMode"); break; case 1: case 2: d->m_account.setValue("priceMode", QString("%1").arg(d->ui->m_priceMode->currentItem())); break; } return d->m_account; } MyMoneyAccount KNewAccountDlg::parentAccount() const { Q_D(const KNewAccountDlg); return d->m_parentAccount; } void KNewAccountDlg::slotSelectionChanged(const QItemSelection ¤t, const QItemSelection &previous) { Q_UNUSED(previous) Q_D(KNewAccountDlg); if (!current.indexes().empty()) { QVariant account = d->ui->m_parentAccounts->model()->data(current.indexes().front(), (int)eAccountsModel::Role::Account); if (account.isValid()) { d->m_parentAccount = account.value(); d->ui->m_subAccountLabel->setText(i18n("Is a sub account of %1", d->m_parentAccount.name())); } } } void KNewAccountDlg::slotLoadInstitutions(const QString& name) { Q_D(KNewAccountDlg); d->ui->m_qcomboboxInstitutions->clear(); QString bic; // Are we forcing the user to use institutions? d->ui->m_qcomboboxInstitutions->addItem(i18n("(No Institution)")); d->ui->m_bicValue->setText(" "); d->ui->ibanEdit->setEnabled(false); d->ui->accountNoEdit->setEnabled(false); try { auto file = MyMoneyFile::instance(); QList list = file->institutionList(); QList::ConstIterator institutionIterator; for (institutionIterator = list.constBegin(); institutionIterator != list.constEnd(); ++institutionIterator) { if ((*institutionIterator).name() == name) { d->ui->ibanEdit->setEnabled(true); d->ui->accountNoEdit->setEnabled(true); d->ui->m_bicValue->setText((*institutionIterator).value("bic")); } d->ui->m_qcomboboxInstitutions->addItem((*institutionIterator).name()); } d->ui->m_qcomboboxInstitutions->setCurrentItem(name, false); } catch (const MyMoneyException &e) { qDebug("Exception in institution load: %s", qPrintable(e.what())); } } void KNewAccountDlg::slotNewClicked() { MyMoneyInstitution institution; QPointer dlg = new KNewBankDlg(institution, this); if (dlg->exec()) { MyMoneyFileTransaction ft; try { auto file = MyMoneyFile::instance(); institution = dlg->institution(); file->addInstitution(institution); ft.commit(); slotLoadInstitutions(institution.name()); } catch (const MyMoneyException &) { KMessageBox::information(this, i18n("Cannot add institution")); } } delete dlg; } void KNewAccountDlg::slotAccountTypeChanged(int index) { Q_D(KNewAccountDlg); Account oldType; auto type = d->ui->typeCombo->itemData(index).value(); try { oldType = d->m_account.accountType(); if (oldType != type) { d->m_account.setAccountType(type); // update the account group displayed in the accounts hierarchy d->m_filterProxyModel->clear(); d->m_filterProxyModel->addAccountGroup(QVector {d->m_account.accountGroup()}); } } catch (const MyMoneyException &) { qWarning("Unexpected exception in KNewAccountDlg::slotAccountTypeChanged()"); } } void KNewAccountDlg::slotCheckFinished() { Q_D(KNewAccountDlg); auto showButton = true; if (d->ui->accountNameEdit->text().length() == 0) { showButton = false; } if (d->ui->m_vatCategory->isChecked() && d->ui->m_vatRate->value() <= MyMoneyMoney()) { showButton = false; } else { if (d->ui->m_vatAssignment->isChecked() && d->ui->m_vatAccount->selectedItems().isEmpty()) showButton = false; } d->ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(showButton); } void KNewAccountDlg::slotVatChanged(bool state) { Q_D(KNewAccountDlg); if (state) { d->ui->m_vatCategoryFrame->show(); d->ui->m_vatAssignmentFrame->hide(); } else { d->ui->m_vatCategoryFrame->hide(); if (!d->m_account.isAssetLiability()) { d->ui->m_vatAssignmentFrame->show(); } } } void KNewAccountDlg::slotVatAssignmentChanged(bool state) { Q_D(KNewAccountDlg); d->ui->m_vatAccount->setEnabled(state); d->ui->m_amountGroupBox->setEnabled(state); } void KNewAccountDlg::slotAdjustMinBalanceAbsoluteEdit(const QString&) { Q_D(KNewAccountDlg); d->adjustEditWidgets(d->ui->m_minBalanceAbsoluteEdit, d->ui->m_minBalanceEarlyEdit, '<', -1); } void KNewAccountDlg::slotAdjustMinBalanceEarlyEdit(const QString&) { Q_D(KNewAccountDlg); d->adjustEditWidgets(d->ui->m_minBalanceEarlyEdit, d->ui->m_minBalanceAbsoluteEdit, '>', -1); } void KNewAccountDlg::slotAdjustMaxCreditAbsoluteEdit(const QString&) { Q_D(KNewAccountDlg); d->adjustEditWidgets(d->ui->m_maxCreditAbsoluteEdit, d->ui->m_maxCreditEarlyEdit, '>', 1); } void KNewAccountDlg::slotAdjustMaxCreditEarlyEdit(const QString&) { Q_D(KNewAccountDlg); d->adjustEditWidgets(d->ui->m_maxCreditEarlyEdit, d->ui->m_maxCreditAbsoluteEdit, '<', 1); } void KNewAccountDlg::slotCheckCurrency(int index) { Q_D(KNewAccountDlg); Q_UNUSED(index) d->handleOpeningBalanceCheckbox(d->ui->m_currency->security().id()); } void KNewAccountDlg::addTab(QWidget* w, const QString& name) { Q_D(KNewAccountDlg); if (w) { w->setParent(d->ui->m_tab); d->ui->m_tab->addTab(w, name); } } diff --git a/kmymoney/dialogs/knewaccountdlg.h b/kmymoney/dialogs/knewaccountdlg.h index 5c2721e6f..d5ab084b0 100644 --- a/kmymoney/dialogs/knewaccountdlg.h +++ b/kmymoney/dialogs/knewaccountdlg.h @@ -1,107 +1,106 @@ /*************************************************************************** knewaccountdlg.h ------------------- copyright : (C) 2000 by Michael Edwardes (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KNEWACCOUNTDLG_H #define KNEWACCOUNTDLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Headers // ---------------------------------------------------------------------------- // Project Includes class QString; class QItemSelection; -class HierarchyFilterProxyModel; class MyMoneyMoney; class MyMoneyAccount; class KNewAccountDlgPrivate; class KNewAccountDlg : public QDialog { Q_OBJECT public: /** * This is the constructor of the dialog. The parameters define the environment * in which the dialog will be used. Depending on the environment, certain rules * apply and will be handled by the dialog. * * @param account The original data to be used to create the account. In case * of @p isEditing is false, the account id, the parent account id * and the list of all child accounts will be cleared. * @param isEditing If @p false, rules for new account creation apply. * If @p true, rules for account editing apply * @param categoryEditor If @p false, rules for asset/liability accounts apply. * If @p true, rules for income/expense account apply. * @param parent Pointer to parent object (passed to QDialog). Default is 0. * @param title Caption of the object (passed to QDialog). Default is empty string. */ KNewAccountDlg(const MyMoneyAccount& account, bool isEditing, bool categoryEditor, QWidget *parent, const QString& title); /** * This method returns the edited account object. */ MyMoneyAccount account(); /** * This method returns the parent account of the edited account object. */ MyMoneyAccount parentAccount() const; MyMoneyMoney openingBalance() const; void setOpeningBalance(const MyMoneyMoney& balance); void setOpeningBalanceShown(bool shown); void setOpeningDateShown(bool shown); /** * This method adds an additional tab pointed to with @a w to the tab widget. * This tab is usually defined by a plugin (eg. online banking). If @a w is * zero, this is a NOP. @a name is used as the text to be placed on the tab. */ void addTab(QWidget* w, const QString& name); protected slots: void okClicked(); void slotSelectionChanged(const QItemSelection ¤t, const QItemSelection &previous); void slotAccountTypeChanged(int index); void slotVatChanged(bool); void slotVatAssignmentChanged(bool); void slotNewClicked(); void slotCheckFinished(); void slotLoadInstitutions(const QString&); void slotAdjustMinBalanceAbsoluteEdit(const QString&); void slotAdjustMinBalanceEarlyEdit(const QString&); void slotAdjustMaxCreditAbsoluteEdit(const QString&); void slotAdjustMaxCreditEarlyEdit(const QString&); void slotCheckCurrency(int index); private: Q_DISABLE_COPY(KNewAccountDlg) Q_DECLARE_PRIVATE(KNewAccountDlg) KNewAccountDlgPrivate* d_ptr; }; #endif diff --git a/kmymoney/dialogs/knewbankdlg.cpp b/kmymoney/dialogs/knewbankdlg.cpp index 0cea4ca7b..ccd40f6a9 100644 --- a/kmymoney/dialogs/knewbankdlg.cpp +++ b/kmymoney/dialogs/knewbankdlg.cpp @@ -1,92 +1,123 @@ /*************************************************************************** knewbankdlg.cpp ------------------- copyright : (C) 2000 by Michael Edwardes email : mte@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "knewbankdlg.h" // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_knewbankdlg.h" + #include "mymoneyinstitution.h" -KNewBankDlg::KNewBankDlg(MyMoneyInstitution& institution, QWidget *parent) - : KNewBankDlgDecl(parent), m_institution(institution) +class KNewBankDlgPrivate +{ + Q_DISABLE_COPY(KNewBankDlgPrivate) + +public: + KNewBankDlgPrivate() : + ui(new Ui::KNewBankDlg) + { + } + + ~KNewBankDlgPrivate() + { + delete ui; + } + + Ui::KNewBankDlg *ui; + MyMoneyInstitution m_institution; +}; + +KNewBankDlg::KNewBankDlg(MyMoneyInstitution& institution, QWidget *parent) : + QDialog(parent), + d_ptr(new KNewBankDlgPrivate) { + Q_D(KNewBankDlg); + d->ui->setupUi(this); + d->m_institution = institution; setModal(true); - nameEdit->setFocus(); - nameEdit->setText(institution.name()); - cityEdit->setText(institution.city()); - streetEdit->setText(institution.street()); - postcodeEdit->setText(institution.postcode()); - telephoneEdit->setText(institution.telephone()); - bicEdit->setText(institution.value("bic")); - sortCodeEdit->setText(institution.sortcode()); - - connect(buttonBox, SIGNAL(accepted()), SLOT(okClicked())); - connect(buttonBox, SIGNAL(rejected()), SLOT(reject())); - connect(nameEdit, SIGNAL(textChanged(QString)), SLOT(institutionNameChanged(QString))); - institutionNameChanged(nameEdit->text()); - - kMandatoryFieldGroup* requiredFields = new kMandatoryFieldGroup(this); - requiredFields->setOkButton(buttonBox->button(QDialogButtonBox::Ok)); // button to be enabled when all fields present - requiredFields->add(nameEdit); + d->ui->nameEdit->setFocus(); + d->ui->nameEdit->setText(institution.name()); + d->ui->cityEdit->setText(institution.city()); + d->ui->streetEdit->setText(institution.street()); + d->ui->postcodeEdit->setText(institution.postcode()); + d->ui->telephoneEdit->setText(institution.telephone()); + d->ui->bicEdit->setText(institution.value("bic")); + d->ui->sortCodeEdit->setText(institution.sortcode()); + + connect(d->ui->buttonBox, &QDialogButtonBox::accepted, this, &KNewBankDlg::okClicked); + connect(d->ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(d->ui->nameEdit, &QLineEdit::textChanged, this, &KNewBankDlg::institutionNameChanged); + institutionNameChanged(d->ui->nameEdit->text()); + + auto requiredFields = new kMandatoryFieldGroup(this); + requiredFields->setOkButton(d->ui->buttonBox->button(QDialogButtonBox::Ok)); // button to be enabled when all fields present + requiredFields->add(d->ui->nameEdit); } void KNewBankDlg::institutionNameChanged(const QString &_text) { - buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!_text.isEmpty()); + Q_D(KNewBankDlg); + d->ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!_text.isEmpty()); } KNewBankDlg::~KNewBankDlg() { + Q_D(KNewBankDlg); + delete d; } void KNewBankDlg::okClicked() { - if (nameEdit->text().isEmpty()) { + Q_D(KNewBankDlg); + if (d->ui->nameEdit->text().isEmpty()) { KMessageBox::information(this, i18n("The institution name field is empty. Please enter the name."), i18n("Adding New Institution")); - nameEdit->setFocus(); + d->ui->nameEdit->setFocus(); return; } - m_institution.setName(nameEdit->text()); - m_institution.setTown(cityEdit->text()); - m_institution.setStreet(streetEdit->text()); - m_institution.setPostcode(postcodeEdit->text()); - m_institution.setTelephone(telephoneEdit->text()); - m_institution.setValue("bic", bicEdit->text()); - m_institution.setSortcode(sortCodeEdit->text()); + d->m_institution.setName(d->ui->nameEdit->text()); + d->m_institution.setTown(d->ui->cityEdit->text()); + d->m_institution.setStreet(d->ui->streetEdit->text()); + d->m_institution.setPostcode(d->ui->postcodeEdit->text()); + d->m_institution.setTelephone(d->ui->telephoneEdit->text()); + d->m_institution.setValue("bic", d->ui->bicEdit->text()); + d->m_institution.setSortcode(d->ui->sortCodeEdit->text()); accept(); } const MyMoneyInstitution& KNewBankDlg::institution() { - return m_institution; + Q_D(KNewBankDlg); + return d->m_institution; } diff --git a/kmymoney/dialogs/knewbankdlg.h b/kmymoney/dialogs/knewbankdlg.h index 54063bc56..a9c4adf02 100644 --- a/kmymoney/dialogs/knewbankdlg.h +++ b/kmymoney/dialogs/knewbankdlg.h @@ -1,63 +1,55 @@ /*************************************************************************** knewbankdlg.h ------------------- copyright : (C) 2000 by Michael Edwardes email : mte@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KNEWBANKDLG_H #define KNEWBANKDLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "mymoneyinstitution.h" - -#include "ui_knewbankdlgdecl.h" - - -class KNewBankDlgDecl : public QDialog, public Ui::KNewBankDlgDecl -{ -public: - explicit KNewBankDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; +class MyMoneyInstitution; /// This dialog lets the user create or edit an institution -class KNewBankDlg : public KNewBankDlgDecl +class KNewBankDlgPrivate; +class KNewBankDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KNewBankDlg) public: - explicit KNewBankDlg(MyMoneyInstitution& institution, QWidget *parent = 0); + explicit KNewBankDlg(MyMoneyInstitution& institution, QWidget *parent = nullptr); ~KNewBankDlg(); const MyMoneyInstitution& institution(); protected slots: void okClicked(); void institutionNameChanged(const QString &); private: - MyMoneyInstitution m_institution; - + KNewBankDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KNewBankDlg) }; #endif diff --git a/kmymoney/dialogs/knewbankdlgdecl.ui b/kmymoney/dialogs/knewbankdlg.ui similarity index 98% rename from kmymoney/dialogs/knewbankdlgdecl.ui rename to kmymoney/dialogs/knewbankdlg.ui index 154030a10..920bffcea 100644 --- a/kmymoney/dialogs/knewbankdlgdecl.ui +++ b/kmymoney/dialogs/knewbankdlg.ui @@ -1,234 +1,234 @@ - KNewBankDlgDecl - + KNewBankDlg + 0 0 631 344 New Institution Dialog true 6 11 11 11 11 Institution Details 11 11 11 11 6 Name: false 100 0 City: false 100 0 Street: false 100 0 Postal Code: false 100 0 Telephone/Fax: false 100 0 Routing Number: false 100 0 BIC false Qt::Vertical QSizePolicy::Expanding 16 16 QFrame::HLine QFrame::Raised 1 QDialogButtonBox::Cancel|QDialogButtonBox::Ok KLineEdit QLineEdit
klineedit.h
diff --git a/kmymoney/dialogs/knewbudgetdlg.cpp b/kmymoney/dialogs/knewbudgetdlg.cpp index a30f46b73..6c50a61be 100644 --- a/kmymoney/dialogs/knewbudgetdlg.cpp +++ b/kmymoney/dialogs/knewbudgetdlg.cpp @@ -1,102 +1,122 @@ /*************************************************************************** knewbudgetdlg.cpp ------------------- begin : Wed Jan 18 2006 copyright : (C) 2000-2004 by Darren Gould email : darren_gould@gmx.de + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "knewbudgetdlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include // ---------------------------------------------------------------------------- // Project Includes -#include "ui_knewbudgetdlgdecl.h" +#include "ui_knewbudgetdlg.h" -struct KNewBudgetDlg::Private { +class KNewBudgetDlgPrivate +{ + Q_DISABLE_COPY(KNewBudgetDlgPrivate) + +public: + KNewBudgetDlgPrivate() : + ui(new Ui::KNewBudgetDlg) + { + } + + ~KNewBudgetDlgPrivate() + { + delete ui; + } + + Ui::KNewBudgetDlg *ui; QString m_year; QString m_name; - - Ui::KNewBudgetDlgDecl ui; }; // the combobox should look m_icNextYears into the future static const int icFutureYears = 5; static const int icPastYears = 2; KNewBudgetDlg::KNewBudgetDlg(QWidget* parent) : - QDialog(parent), d(new Private) + QDialog(parent), + d_ptr(new KNewBudgetDlgPrivate) { - d->ui.setupUi(this); + Q_D(KNewBudgetDlg); + d->ui->setupUi(this); QStringList slYear; - QDate dToday = QDate::currentDate(); - int iYear = dToday.year(); + auto dToday = QDate::currentDate(); + auto iYear = dToday.year(); - for (int i = 0; i <= icFutureYears; i++) - d->ui.m_cbYear->addItem(QString::number(iYear++)); + for (auto i = 0; i <= icFutureYears; i++) + d->ui->m_cbYear->addItem(QString::number(iYear++)); iYear = dToday.year(); - for (int i = 0; i <= icPastYears; i++) - d->ui.m_cbYear->addItem(QString::number(--iYear)); + for (auto i = 0; i <= icPastYears; i++) + d->ui->m_cbYear->addItem(QString::number(--iYear)); - connect(d->ui.buttonBox, SIGNAL(accepted()), this, SLOT(m_pbOk_clicked())); - connect(d->ui.buttonBox, SIGNAL(rejected()), this, SLOT(m_pbCancel_clicked())); + connect(d->ui->buttonBox, &QDialogButtonBox::accepted, this, &KNewBudgetDlg::m_pbOk_clicked); + connect(d->ui->buttonBox, &QDialogButtonBox::rejected, this, &KNewBudgetDlg::m_pbCancel_clicked); } KNewBudgetDlg::~KNewBudgetDlg() { + Q_D(KNewBudgetDlg); delete d; } void KNewBudgetDlg::m_pbCancel_clicked() { reject(); } void KNewBudgetDlg::m_pbOk_clicked() { + Q_D(KNewBudgetDlg); // force focus change to update all data - d->ui.buttonBox->button(QDialogButtonBox::Ok)->setFocus(); + d->ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); - if (d->ui.m_leBudgetName->displayText().isEmpty()) { + if (d->ui->m_leBudgetName->displayText().isEmpty()) { KMessageBox::information(this, i18n("Please specify a budget name")); - d->ui.m_leBudgetName->setFocus(); + d->ui->m_leBudgetName->setFocus(); return; } - d->m_year = d->ui.m_cbYear->currentText(); - d->m_name = d->ui.m_leBudgetName->displayText(); + d->m_year = d->ui->m_cbYear->currentText(); + d->m_name = d->ui->m_leBudgetName->displayText(); accept(); } -QString& KNewBudgetDlg::getYear() +QString KNewBudgetDlg::getYear() const { + Q_D(const KNewBudgetDlg); return d->m_year; } -QString& KNewBudgetDlg::getName() +QString KNewBudgetDlg::getName() const { + Q_D(const KNewBudgetDlg); return d->m_name; } diff --git a/kmymoney/dialogs/knewbudgetdlg.h b/kmymoney/dialogs/knewbudgetdlg.h index e5f647ed4..68dea01f2 100644 --- a/kmymoney/dialogs/knewbudgetdlg.h +++ b/kmymoney/dialogs/knewbudgetdlg.h @@ -1,52 +1,55 @@ /*************************************************************************** knewbudgetdlg.h ------------------- begin : Wed Jan 18 2006 copyright : (C) 2000-2004 by Darren Gould email : darren_gould@gmx.de + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KNEWBUDGETDLG_H #define KNEWBUDGETDLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes +class KNewBudgetDlgPrivate; class KNewBudgetDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KNewBudgetDlg) public: - KNewBudgetDlg(QWidget* parent); + explicit KNewBudgetDlg(QWidget* parent = nullptr); ~KNewBudgetDlg(); - QString& getYear(); - QString& getName(); + QString getYear() const; + QString getName() const; public slots: - virtual void m_pbCancel_clicked(); - virtual void m_pbOk_clicked(); + void m_pbCancel_clicked(); + void m_pbOk_clicked(); private: - struct Private; - Private* const d; + KNewBudgetDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KNewBudgetDlg) }; #endif // KNEWBUDGETDLG_H diff --git a/kmymoney/dialogs/knewbudgetdlgdecl.ui b/kmymoney/dialogs/knewbudgetdlg.ui similarity index 96% rename from kmymoney/dialogs/knewbudgetdlgdecl.ui rename to kmymoney/dialogs/knewbudgetdlg.ui index 8bd460728..11f2d9634 100644 --- a/kmymoney/dialogs/knewbudgetdlgdecl.ui +++ b/kmymoney/dialogs/knewbudgetdlg.ui @@ -1,96 +1,96 @@ - KNewBudgetDlgDecl - + KNewBudgetDlg + 0 0 283 116 New Budget true Name false Year false 0 0 -1 QDialogButtonBox::Cancel|QDialogButtonBox::Ok KLineEdit QLineEdit
klineedit.h
KComboBox QComboBox
kcombobox.h
diff --git a/kmymoney/dialogs/knewequityentrydecl.ui b/kmymoney/dialogs/knewequityentrydecl.ui deleted file mode 100644 index 38ace038c..000000000 --- a/kmymoney/dialogs/knewequityentrydecl.ui +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - kNewEquityEntryDecl - - - - 0 - 0 - 417 - 208 - - - - New Equity - - - true - - - - - - - - Equity Name: - - - false - - - - - - - Investment Type: - - - false - - - - - - - Trading Symbol of the stock or mutual fund, not required. - - - Trading Symbol of the stock or mutual fund, not required. - - - - - - - - - - 1 - 5 - 0 - 0 - - - - 1 / - - - Qt::AlignVCenter|Qt::AlignRight - - - false - - - - - - - - - - - - Market Symbol: - - - false - - - - - - - Smallest fraction: - - - false - - - - - - - - Stock - - - - - Mutual Fund - - - - - Bond - - - - - - - - Name of the company, or mutual fund. - - - Name of the company, or mutual fund. - - - - - - - - - - 20 - 16 - - - - QSizePolicy::Expanding - - - Qt::Vertical - - - - - - - - - - 81 - 20 - - - - QSizePolicy::Expanding - - - Qt::Horizontal - - - - - - - OK - - - - - - - Cancel - - - - - - - - - - - kMyMoneyEdit - QWidget -
../widgets/kmymoneyedit.h
- - 90 - 25 - - 0 - - 1 - 1 - - image0 -
- - KComboBox - QComboBox -
kcombobox.h
-
-
- - edtEquityName - edtMarketSymbol - cmbInvestmentType - btnOK - btnCancel - - - - 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000000c749444154789cad55db1184200c4c180bb005eab1cd6b8112b40d4bf1bee2486ef3006fbf1c93ece605f07eece4e1a4ed42ff2b35f6e2961132e46309941952ed8f628a761a21f56217cb20b04a45fe276d97f8ffb422431ad96e62a4ee057a83131bcc38431a6d057f8eb5cb36438afcb5cded719614011e9088308374c61aa9adb0e0651b5552b4b29efaacb099312ad5da5b2d50a93124463b2adf516fbb8cbd1354a9b1b667c8a787674144f9f982bcb93635ba8cb3fd1b2616f251013403fee763fabce8bff0aa6c989d7e67440000000049454e44ae426082 - - -
diff --git a/kmymoney/dialogs/knewequityentrydlg.cpp b/kmymoney/dialogs/knewequityentrydlg.cpp index 2aad7dfad..c5076024d 100644 --- a/kmymoney/dialogs/knewequityentrydlg.cpp +++ b/kmymoney/dialogs/knewequityentrydlg.cpp @@ -1,102 +1,149 @@ /*************************************************************************** knewequityentrydlg.cpp - description ------------------- begin : Tue Jan 29 2002 copyright : (C) 2000-2002 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "knewequityentrydlg.h" // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes -#include -#include - // ---------------------------------------------------------------------------- // Project Includes +#include "ui_knewequityentrydlg.h" + #include "kmymoneyedit.h" #include "mymoneymoney.h" -KNewEquityEntryDlg::KNewEquityEntryDlg(QWidget *parent) - : kNewEquityEntryDecl(parent), - m_fraction(0) +class KNewEquityEntryDlgPrivate +{ + Q_DISABLE_COPY(KNewEquityEntryDlgPrivate) + Q_DECLARE_PUBLIC(KNewEquityEntryDlg) + +public: + KNewEquityEntryDlgPrivate() : + ui(new Ui::KNewEquityEntryDlg) + { + } + + ~KNewEquityEntryDlgPrivate() + { + delete ui; + } + + KNewEquityEntryDlg *q_ptr; + Ui::KNewEquityEntryDlg *ui; + QString m_strSymbolName; + QString m_strName; + int m_fraction; +}; + +KNewEquityEntryDlg::KNewEquityEntryDlg(QWidget *parent) : + QDialog(parent), + d_ptr(new KNewEquityEntryDlgPrivate) { + Q_D(KNewEquityEntryDlg); + d->m_fraction = 0; + d->ui->setupUi(this); setModal(true); - edtFraction->setCalculatorButtonVisible(false); - edtFraction->setPrecision(0); - edtFraction->loadText("100"); + d->ui->edtFraction->setCalculatorButtonVisible(false); + d->ui->edtFraction->setPrecision(0); + d->ui->edtFraction->loadText("100"); - connect(btnOK, SIGNAL(clicked()), this, SLOT(onOKClicked())); - connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject())); + connect(d->ui->buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, &KNewEquityEntryDlg::onOKClicked); - connect(edtFraction, SIGNAL(textChanged(QString)), this, SLOT(slotDataChanged())); - connect(edtMarketSymbol, SIGNAL(textChanged(QString)), this, SLOT(slotDataChanged())); - connect(edtEquityName, SIGNAL(textChanged(QString)), this, SLOT(slotDataChanged())); + connect(d->ui->edtFraction, &kMyMoneyEdit::textChanged, this, &KNewEquityEntryDlg::slotDataChanged); + connect(d->ui->edtMarketSymbol, &QLineEdit::textChanged, this, &KNewEquityEntryDlg::slotDataChanged); + connect(d->ui->edtEquityName, &QLineEdit::textChanged, this, &KNewEquityEntryDlg::slotDataChanged); // add icons to buttons - KGuiItem::assign(btnOK, KStandardGuiItem::ok()); - KGuiItem::assign(btnCancel, KStandardGuiItem::cancel()); slotDataChanged(); - edtEquityName->setFocus(); + d->ui->edtEquityName->setFocus(); } KNewEquityEntryDlg::~KNewEquityEntryDlg() { + Q_D(KNewEquityEntryDlg); + delete d; } /** No descriptions */ void KNewEquityEntryDlg::onOKClicked() { - m_strSymbolName = edtMarketSymbol->text(); - m_strName = edtEquityName->text(); - m_fraction = edtFraction->value().abs().formatMoney("", 0, false).toUInt(); + Q_D(KNewEquityEntryDlg); + d->m_strSymbolName = d->ui->edtMarketSymbol->text(); + d->m_strName = d->ui->edtEquityName->text(); + d->m_fraction = d->ui->edtFraction->value().abs().formatMoney("", 0, false).toUInt(); accept(); } void KNewEquityEntryDlg::setSymbolName(const QString& str) { - m_strSymbolName = str; - edtMarketSymbol->setText(m_strSymbolName); + Q_D(KNewEquityEntryDlg); + d->m_strSymbolName = str; + d->ui->edtMarketSymbol->setText(d->m_strSymbolName); +} + +QString KNewEquityEntryDlg::symbolName() const +{ + Q_D(const KNewEquityEntryDlg); + return d->m_strSymbolName; } void KNewEquityEntryDlg::setName(const QString& str) { - m_strName = str; - edtEquityName->setText(m_strName); + Q_D(KNewEquityEntryDlg); + d->m_strName = str; + d->ui->edtEquityName->setText(d->m_strName); +} + +QString KNewEquityEntryDlg::name() const +{ + Q_D(const KNewEquityEntryDlg); + return d->m_strName; +} + +int KNewEquityEntryDlg::fraction() const +{ + Q_D(const KNewEquityEntryDlg); + return d->m_fraction; } void KNewEquityEntryDlg::slotDataChanged() { - bool okEnabled = true; + Q_D(KNewEquityEntryDlg); + auto okEnabled = true; - if (!edtFraction->value().isPositive() - || edtMarketSymbol->text().isEmpty() - || edtEquityName->text().isEmpty()) + if (!d->ui->edtFraction->value().isPositive() + || d->ui->edtMarketSymbol->text().isEmpty() + || d->ui->edtEquityName->text().isEmpty()) okEnabled = false; - btnOK->setEnabled(okEnabled); + d->ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(okEnabled); } diff --git a/kmymoney/dialogs/knewequityentrydlg.h b/kmymoney/dialogs/knewequityentrydlg.h index 1b6347e27..ac7f66977 100644 --- a/kmymoney/dialogs/knewequityentrydlg.h +++ b/kmymoney/dialogs/knewequityentrydlg.h @@ -1,77 +1,64 @@ /*************************************************************************** knewequityentrydlg.h - description ------------------- begin : Tue Jan 29 2002 copyright : (C) 2000-2002 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ -#ifndef KNEWEQUITYENTRY_H -#define KNEWEQUITYENTRY_H +#ifndef KNEWEQUITYENTRYDLG_H +#define KNEWEQUITYENTRYDLG_H #include -#include "ui_knewequityentrydecl.h" - /** * * Dialog to allow user to enter all data for a stock or mutual fund investment type. * * @author Kevin Tambascio * */ -class kNewEquityEntryDecl : public QDialog, public Ui::kNewEquityEntryDecl -{ -public: - kNewEquityEntryDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; - -class KNewEquityEntryDlg : public kNewEquityEntryDecl +class KNewEquityEntryDlgPrivate; +class KNewEquityEntryDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KNewEquityEntryDlg) + public: - KNewEquityEntryDlg(QWidget *parent = 0); + explicit KNewEquityEntryDlg(QWidget *parent = nullptr); virtual ~KNewEquityEntryDlg(); void setSymbolName(const QString& str); - QString symbolName() const { - return m_strSymbolName; - } + QString symbolName() const; void setName(const QString& str); - QString name() const { - return m_strName; - } + QString name() const; - int fraction() const { - return m_fraction; - } + int fraction() const; protected slots: void onOKClicked(); void slotDataChanged(); private: - QString m_strSymbolName; - QString m_strName; - int m_fraction; + KNewEquityEntryDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KNewEquityEntryDlg) }; #endif diff --git a/kmymoney/dialogs/knewequityentrydlg.ui b/kmymoney/dialogs/knewequityentrydlg.ui new file mode 100644 index 000000000..125d5be29 --- /dev/null +++ b/kmymoney/dialogs/knewequityentrydlg.ui @@ -0,0 +1,197 @@ + + + KNewEquityEntryDlg + + + + 0 + 0 + 417 + 208 + + + + New Equity + + + true + + + + + + + + Equity Name: + + + false + + + + + + + Investment Type: + + + false + + + + + + + Trading Symbol of the stock or mutual fund, not required. + + + Trading Symbol of the stock or mutual fund, not required. + + + + + + + + + + 0 + 0 + + + + 1 / + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + + + + + Market Symbol: + + + false + + + + + + + Smallest fraction: + + + false + + + + + + + + Stock + + + + + Mutual Fund + + + + + Bond + + + + + + + + Name of the company, or mutual fund. + + + Name of the company, or mutual fund. + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 16 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + KComboBox + QComboBox +
kcombobox.h
+
+ + KLineEdit + QLineEdit +
klineedit.h
+
+ + kMyMoneyEdit + QWidget +
kmymoneyedit.h
+ 1 +
+
+ + edtEquityName + edtMarketSymbol + cmbInvestmentType + + + + + buttonBox + rejected() + KNewEquityEntryDlg + reject() + + + 208 + 184 + + + 208 + 103 + + + + +
diff --git a/kmymoney/dialogs/konlinetransferform.cpp b/kmymoney/dialogs/konlinetransferform.cpp index e216f19d7..7fc4b654c 100644 --- a/kmymoney/dialogs/konlinetransferform.cpp +++ b/kmymoney/dialogs/konlinetransferform.cpp @@ -1,333 +1,331 @@ /* * This file is part of KMyMoney, A Personal Finance Manager by KDE * Copyright (C) 2014 Christian Dávid + * (C) 2017 by Ł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 "konlinetransferform.h" -#include "ui_konlinetransferformdecl.h" +#include "ui_konlinetransferform.h" #include -#include -#include -#include +#include +#include #include #include #include #include #include "kguiutils.h" -#include "kmymoneylineedit.h" #include "onlinetasks/interfaces/ui/ionlinejobedit.h" -#include "mymoney/mymoneyfile.h" -#include "mymoney/mymoneyaccount.h" +#include "mymoneyfile.h" #include "mymoney/onlinejobadministration.h" #include "onlinejob.h" #include "tasks/onlinetask.h" #include "accountsmodel.h" #include "models/models.h" #include "icons/icons.h" using namespace Icons; kOnlineTransferForm::kOnlineTransferForm(QWidget *parent) : QDialog(parent), - ui(new Ui::kOnlineTransferFormDecl), + ui(new Ui::kOnlineTransferForm), m_onlineJobEditWidgets(QList()), m_requiredFields(new kMandatoryFieldGroup(this)) { ui->setupUi(this); ui->unsupportedIcon->setPixmap(QIcon::fromTheme(g_Icons[Icon::DialogInformation]).pixmap(style()->pixelMetric(QStyle::PM_MessageBoxIconSize))); // The ui designer fills the QScrollArea with a QWidget. Remove it so we can simply check for .widget() == nullptr // if it contains a valid widget delete ui->creditTransferEdit->takeWidget(); OnlineBankingAccountNamesFilterProxyModel* accountsModel = new OnlineBankingAccountNamesFilterProxyModel(this); auto const model = Models::instance()->accountsModel(); accountsModel->setSourceModel(model); ui->originAccount->setModel(accountsModel); ui->convertMessage->hide(); ui->convertMessage->setWordWrap(true); auto edits = onlineJobAdministration::instance()->onlineJobEdits(); std::for_each(edits.constBegin(), edits.constEnd(), [this](onlineJobAdministration::onlineJobEditOffer in) {this->loadOnlineJobEditPlugin(in);}); // Message Widget for read only jobs m_duplicateJob = KStandardAction::copy(this); - connect(m_duplicateJob, SIGNAL(triggered(bool)), SLOT(duplicateCurrentJob())); + connect(m_duplicateJob, &QAction::triggered, this, &kOnlineTransferForm::duplicateCurrentJob); ui->headMessage->hide(); ui->headMessage->setWordWrap(true); ui->headMessage->setCloseButtonVisible(false); ui->headMessage->addAction(m_duplicateJob); - connect(ui->transferTypeSelection, SIGNAL(currentIndexChanged(int)), this, SLOT(convertCurrentJob(int))); + connect(ui->transferTypeSelection, static_cast(&QComboBox::currentIndexChanged), this, &kOnlineTransferForm::convertCurrentJob); - connect(ui->buttonAbort, SIGNAL(clicked(bool)), this, SLOT(reject())); - connect(ui->buttonSend, SIGNAL(clicked(bool)), this, SLOT(sendJob())); - connect(ui->buttonEnque, SIGNAL(clicked(bool)), this, SLOT(accept())); - connect(m_requiredFields, SIGNAL(stateChanged(bool)), ui->buttonEnque, SLOT(setEnabled(bool))); + connect(ui->buttonAbort, &QAbstractButton::clicked, this, &kOnlineTransferForm::reject); + connect(ui->buttonSend, &QAbstractButton::clicked, this, &kOnlineTransferForm::sendJob); + connect(ui->buttonEnque, &QAbstractButton::clicked, this, &kOnlineTransferForm::accept); + connect(m_requiredFields, static_cast(&kMandatoryFieldGroup::stateChanged), ui->buttonEnque, &QPushButton::setEnabled); - connect(ui->originAccount, SIGNAL(accountSelected(QString)), this, SLOT(accountChanged())); + connect(ui->originAccount, &KMyMoneyAccountCombo::accountSelected, this, &kOnlineTransferForm::accountChanged); accountChanged(); setJobReadOnly(false); m_requiredFields->add(ui->originAccount); m_requiredFields->setOkButton(ui->buttonSend); } void kOnlineTransferForm::loadOnlineJobEditPlugin(const onlineJobAdministration::onlineJobEditOffer& pluginDesc) { try { std::unique_ptr loader{new QPluginLoader(pluginDesc.fileName, this)}; QObject* plugin = loader->instance(); if (!plugin) { qWarning() << "Could not load plugin for online job editor from file \"" << pluginDesc.fileName << "\"."; return; } // Cast to KPluginFactory KPluginFactory* pluginFactory = qobject_cast< KPluginFactory* >(plugin); if (!pluginFactory) { qWarning() << "Could not create plugin factory for online job editor in file \"" << pluginDesc.fileName << "\"."; return; } IonlineJobEdit* widget = pluginFactory->create(pluginDesc.pluginKeyword, this); if (!widget) { qWarning() << "Could not create online job editor in file \"" << pluginDesc.fileName << "\"."; return; } // directly load the first widget into QScrollArea bool showWidget = true; if (!m_onlineJobEditWidgets.isEmpty()) { widget->setEnabled(false); showWidget = false; } m_onlineJobEditWidgets.append(widget); ui->transferTypeSelection->addItem(pluginDesc.name); m_requiredFields->add(widget); if (showWidget) showEditWidget(widget); } catch (MyMoneyException& e) { qWarning("Error while loading a plugin (IonlineJobEdit)."); } } void kOnlineTransferForm::convertCurrentJob(const int& index) { Q_ASSERT(index < m_onlineJobEditWidgets.count()); IonlineJobEdit* widget = m_onlineJobEditWidgets.at(index); // Vars set by onlineJobAdministration::convertBest onlineTaskConverter::convertType convertType; QString userMessage; widget->setOnlineJob(onlineJobAdministration::instance()->convertBest(activeOnlineJob(), widget->supportedOnlineTasks(), convertType, userMessage)); if (convertType == onlineTaskConverter::convertImpossible && userMessage.isEmpty()) userMessage = i18n("During the change of the order your previous entries could not be converted."); if (!userMessage.isEmpty()) { switch (convertType) { case onlineTaskConverter::convertionLossyMajor: ui->convertMessage->setMessageType(KMessageWidget::Warning); break; case onlineTaskConverter::convertImpossible: case onlineTaskConverter::convertionLossyMinor: ui->convertMessage->setMessageType(KMessageWidget::Information); break; case onlineTaskConverter::convertionLoseless: break; } ui->convertMessage->setText(userMessage); ui->convertMessage->animatedShow(); } showEditWidget(widget); } void kOnlineTransferForm::duplicateCurrentJob() { IonlineJobEdit* widget = qobject_cast< IonlineJobEdit* >(ui->creditTransferEdit->widget()); if (widget == 0) return; onlineJob duplicate(QString(), activeOnlineJob()); widget->setOnlineJob(duplicate); } void kOnlineTransferForm::accept() { emit acceptedForSave(activeOnlineJob()); QDialog::accept(); } void kOnlineTransferForm::sendJob() { emit acceptedForSend(activeOnlineJob()); QDialog::accept(); } void kOnlineTransferForm::reject() { QDialog::reject(); } bool kOnlineTransferForm::setOnlineJob(const onlineJob job) { QString name; try { name = job.task()->taskName(); } catch (const onlineJob::emptyTask&) { return false; } setCurrentAccount(job.responsibleAccount()); if (showEditWidget(name)) { IonlineJobEdit* widget = qobject_cast(ui->creditTransferEdit->widget()); if (widget != 0) { // This can happen if there are no widgets const bool ret = widget->setOnlineJob(job); setJobReadOnly(!job.isEditable()); return ret; } } return false; } void kOnlineTransferForm::accountChanged() { const QString accountId = ui->originAccount->getSelected(); try { ui->orderAccountBalance->setValue(MyMoneyFile::instance()->balance(accountId)); } catch (const MyMoneyException&) { // @todo this can happen until the selection allows to select correct accounts only ui->orderAccountBalance->setText(""); } foreach (IonlineJobEdit* widget, m_onlineJobEditWidgets) widget->setOriginAccount(accountId); checkNotSupportedWidget(); } bool kOnlineTransferForm::checkEditWidget() { return checkEditWidget(qobject_cast(ui->creditTransferEdit->widget())); } bool kOnlineTransferForm::checkEditWidget(IonlineJobEdit* widget) { if (widget != 0 && onlineJobAdministration::instance()->isJobSupported(ui->originAccount->getSelected(), widget->supportedOnlineTasks())) { return true; } return false; } /** @todo auto set another widget if a loseless convert is possible */ void kOnlineTransferForm::checkNotSupportedWidget() { if (!checkEditWidget()) { ui->displayStack->setCurrentIndex(0); } else { ui->displayStack->setCurrentIndex(1); } } void kOnlineTransferForm::setCurrentAccount(const QString& accountId) { ui->originAccount->setSelected(accountId); } onlineJob kOnlineTransferForm::activeOnlineJob() const { IonlineJobEdit* widget = qobject_cast(ui->creditTransferEdit->widget()); if (widget == 0) return onlineJob(); return widget->getOnlineJob(); } void kOnlineTransferForm::setJobReadOnly(const bool& readOnly) { ui->originAccount->setDisabled(readOnly); ui->transferTypeSelection->setDisabled(readOnly); if (readOnly) { ui->headMessage->setMessageType(KMessageWidget::Information); if (activeOnlineJob().sendDate().isValid()) ui->headMessage->setText(i18n("This credit-transfer was sent to your bank at %1 therefore cannot be edited anymore. You may create a copy for editing.").arg(activeOnlineJob().sendDate().toString(Qt::DefaultLocaleShortDate))); else ui->headMessage->setText(i18n("This credit-transfer is not editable. You may create a copy for editing.")); if (this->isHidden()) ui->headMessage->show(); else ui->headMessage->animatedShow(); } else { ui->headMessage->animatedHide(); } } bool kOnlineTransferForm::showEditWidget(const QString& onlineTaskName) { int index = 0; foreach (IonlineJobEdit* widget, m_onlineJobEditWidgets) { if (widget->supportedOnlineTasks().contains(onlineTaskName)) { ui->transferTypeSelection->setCurrentIndex(index); showEditWidget(widget); return true; } ++index; } return false; } void kOnlineTransferForm::showEditWidget(IonlineJobEdit* widget) { Q_CHECK_PTR(widget); QWidget* oldWidget = ui->creditTransferEdit->takeWidget(); if (oldWidget != 0) { // This is true at the first call of showEditWidget() and if there are no widgets. oldWidget->setEnabled(false); - disconnect(oldWidget, SIGNAL(readOnlyChanged(bool)), this, SLOT(setJobReadOnly(bool))); + disconnect(qobject_cast(oldWidget), &IonlineJobEdit::readOnlyChanged, this, &kOnlineTransferForm::setJobReadOnly); } widget->setEnabled(true); ui->creditTransferEdit->setWidget(widget); setJobReadOnly(widget->isReadOnly()); widget->show(); - connect(widget, SIGNAL(readOnlyChanged(bool)), SLOT(setJobReadOnly(bool))); + connect(widget, &IonlineJobEdit::readOnlyChanged, this, &kOnlineTransferForm::setJobReadOnly); checkNotSupportedWidget(); m_requiredFields->changed(); } kOnlineTransferForm::~kOnlineTransferForm() { ui->creditTransferEdit->takeWidget(); qDeleteAll(m_onlineJobEditWidgets); delete ui; delete m_duplicateJob; } diff --git a/kmymoney/dialogs/konlinetransferform.h b/kmymoney/dialogs/konlinetransferform.h index a968ff864..e4bc2d9ba 100644 --- a/kmymoney/dialogs/konlinetransferform.h +++ b/kmymoney/dialogs/konlinetransferform.h @@ -1,139 +1,137 @@ /* * This file is part of KMyMoney, A Personal Finance Manager by KDE * Copyright (C) 2014 Christian Dávid + * (C) 2017 by Ł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 KONLINETRANSFERFORM_H #define KONLINETRANSFERFORM_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // Project Includes #include "mymoney/onlinejob.h" #include "mymoney/onlinejobadministration.h" class IonlineJobEdit; class kMandatoryFieldGroup; -namespace Ui -{ -class kOnlineTransferFormDecl; -} +namespace Ui { class kOnlineTransferForm; } /** * @brief The kOnlineTransferForm class * * @todo Disable Send/Enque button if no task is shown. * @todo If this dialog is shown a second time without setting a onlineJob it, it shows the previous content. * Fix this by creating the IonlineJobEdit widgets on demand and destroying them afterwards. */ class kOnlineTransferForm : public QDialog { Q_OBJECT public: - kOnlineTransferForm(QWidget *parent = 0); + kOnlineTransferForm(QWidget *parent = nullptr); virtual ~kOnlineTransferForm(); signals: /** @brief The user wants this job to be saved */ void acceptedForSave(onlineJob); /** @brief User wants to send the onlineJob directly */ void acceptedForSend(onlineJob); public slots: virtual void accept(); virtual void reject(); /** @brief sets the current origin account */ virtual void setCurrentAccount(const QString& accountId); /** * @brief Sets an onlineTransfer to edit * * @return true if there is widget which supports editing this onlineJob */ virtual bool setOnlineJob(const onlineJob); void duplicateCurrentJob(); private slots: /** @brief Slot for account selection box */ void accountChanged(); /** * @brief Slot to change job type * @param index of KComboBox (== index of selected widget in m_onlineJobEditWidgets) */ void convertCurrentJob(const int& index); /** @brief Slot for send button */ void sendJob(); /** * @brief Load a plugin */ void loadOnlineJobEditPlugin(const onlineJobAdministration::onlineJobEditOffer& plugin); /** @{ */ /** * @brief Activates the onlineJobEdit widget */ bool showEditWidget(const QString& onlineTaskName); void showEditWidget(IonlineJobEdit* widget); /** @} */ /** * @brief Shows warning if checkEditWidget() == false */ void checkNotSupportedWidget(); void setJobReadOnly(const bool&); private: /** * @brief returns the currently edited onlineJob * Can be a null job */ onlineJob activeOnlineJob() const; - Ui::kOnlineTransferFormDecl* ui; + Ui::kOnlineTransferForm* ui; QList m_onlineJobEditWidgets; kMandatoryFieldGroup* m_requiredFields; QAction* m_duplicateJob; /** * @brief Checks if widget can edit any task the selected account supports */ bool checkEditWidget(IonlineJobEdit* widget); /** * @brief Checks current widget * @see checkEditWidget( IonlineJobEdit* widget ) */ bool checkEditWidget(); void editWidgetChanged(); }; #endif // KONLINETRANSFERFORM_H diff --git a/kmymoney/dialogs/konlinetransferformdecl.ui b/kmymoney/dialogs/konlinetransferform.ui similarity index 98% rename from kmymoney/dialogs/konlinetransferformdecl.ui rename to kmymoney/dialogs/konlinetransferform.ui index 304b8997e..56acbe416 100644 --- a/kmymoney/dialogs/konlinetransferformdecl.ui +++ b/kmymoney/dialogs/konlinetransferform.ui @@ -1,301 +1,301 @@ - kOnlineTransferFormDecl - + kOnlineTransferForm + 0 0 624 617 false Order Account Account Balance false false false true Credit Transfer 0 0 333 250 0 Qt::Vertical 20 54 Qt::Horizontal 0 20 QLayout::SetMaximumSize 0 0 300 16777215 <html><head/><body><p>This account does not support online banking.</p><p>If you think this is an error, please check if the plugin for this type of credit transfer and your online banking plugins are available.</p></body></html> true Qt::Horizontal 0 20 Qt::Vertical 20 53 QFrame::NoFrame QFrame::Plain true Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 0 0 75 16 Qt::Horizontal 40 20 Enqueue false Send Abort kMyMoneyEdit QFrame
kmymoneyedit.h
1
KMyMoneyAccountCombo KComboBox
kmymoneyaccountcombo.h
KComboBox QComboBox
kcombobox.h
KMessageWidget QWidget
KMessageWidget
1
buttonSend buttonEnque buttonAbort
diff --git a/kmymoney/dialogs/kpayeereassigndlg.cpp b/kmymoney/dialogs/kpayeereassigndlg.cpp index 0cfb80f51..364341c0d 100644 --- a/kmymoney/dialogs/kpayeereassigndlg.cpp +++ b/kmymoney/dialogs/kpayeereassigndlg.cpp @@ -1,89 +1,124 @@ /*************************************************************************** kpayeereassigndlg.cpp ------------------- copyright : (C) 2005 by Andreas Nicolai (C) 2007 by Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kpayeereassigndlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kpayeereassigndlg.h" + #include /** This lookup table needs to be in sync with KPayeeReassignDlg::OperationType enum */ static const char * labelText[KPayeeReassignDlg::TypeCount] = { I18N_NOOP("To be able to merge previous selected payees, please select a payee from the list below or create a new one."), I18N_NOOP("The transactions associated with the selected payees need to be re-assigned to a different payee before the selected payees can be deleted. Please select a payee from the list below."), }; +class KPayeeReassignDlgPrivate +{ + Q_DISABLE_COPY(KPayeeReassignDlgPrivate) + +public: + KPayeeReassignDlgPrivate() : + ui(new Ui::KPayeeReassignDlg) + { + } + + ~KPayeeReassignDlgPrivate() + { + delete ui; + } + + Ui::KPayeeReassignDlg *ui; + KPayeeReassignDlg::OperationType m_type; +}; + KPayeeReassignDlg::KPayeeReassignDlg(KPayeeReassignDlg::OperationType type, QWidget* parent) : - KPayeeReassignDlgDecl(parent), - m_type(type) + QDialog(parent), + d_ptr(new KPayeeReassignDlgPrivate) { - kMandatoryFieldGroup* mandatory = new kMandatoryFieldGroup(this); - mandatory->add(payeeCombo); - mandatory->setOkButton(buttonBox->button(QDialogButtonBox::Ok)); - textLabel1->setText(i18n(labelText[m_type])); + Q_D(KPayeeReassignDlg); + d->ui->setupUi(this); + d->m_type = type; + auto mandatory = new kMandatoryFieldGroup(this); + mandatory->add(d->ui->payeeCombo); + mandatory->setOkButton(d->ui->buttonBox->button(QDialogButtonBox::Ok)); + d->ui->textLabel1->setText(i18n(labelText[d->m_type])); } KPayeeReassignDlg::~KPayeeReassignDlg() { + Q_D(KPayeeReassignDlg); + delete d; } QString KPayeeReassignDlg::show(const QList& payeeslist) { + Q_D(KPayeeReassignDlg); if (payeeslist.isEmpty()) return QString(); // no payee available? nothing can be selected... - payeeCombo->loadPayees(payeeslist); + d->ui->payeeCombo->loadPayees(payeeslist); // execute dialog and if aborted, return empty string if (this->exec() == QDialog::Rejected) return QString(); // allow to return the text (new payee) if type is Merge - if (m_type == TypeMerge && payeeCombo->selectedItem().isEmpty()) - return payeeCombo->lineEdit()->text(); + if (d->m_type == TypeMerge && d->ui->payeeCombo->selectedItem().isEmpty()) + return d->ui->payeeCombo->lineEdit()->text(); // otherwise return index of selected payee - return payeeCombo->selectedItem(); + return d->ui->payeeCombo->selectedItem(); } +bool KPayeeReassignDlg::addToMatchList() const +{ + Q_D(const KPayeeReassignDlg); + return d->ui->m_copyToMatchList->isChecked(); +} + void KPayeeReassignDlg::accept() { - // force update of payeeCombo - buttonBox->button(QDialogButtonBox::Ok)->setFocus(); + Q_D(KPayeeReassignDlg); + // force update of d->ui->payeeCombo + d->ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); - if (m_type == TypeDelete && payeeCombo->selectedItem().isEmpty()) { + if (d->m_type == TypeDelete && d->ui->payeeCombo->selectedItem().isEmpty()) { KMessageBox::information(this, i18n("This dialog does not allow new payees to be created. Please pick a payee from the list."), i18n("Payee creation")); } else { - KPayeeReassignDlgDecl::accept(); + QDialog::accept(); } } diff --git a/kmymoney/dialogs/kpayeereassigndlg.h b/kmymoney/dialogs/kpayeereassigndlg.h index 6e6c1985b..d1044121e 100644 --- a/kmymoney/dialogs/kpayeereassigndlg.h +++ b/kmymoney/dialogs/kpayeereassigndlg.h @@ -1,92 +1,85 @@ /*************************************************************************** kpayeereassigndlg.cpp ------------------- copyright : (C) 2005 by Andreas Nicolai (C) 2007 by Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KPAYEEREASSIGNDLG_H #define KPAYEEREASSIGNDLG_H // ---------------------------------------------------------------------------- // QT Includes -#include +#include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_kpayeereassigndlgdecl.h" - /** * Implementation of the dialog that lets the user select a payee in order * to re-assign transactions (for instance, if payees are deleted). */ class MyMoneyPayee; -class KPayeeReassignDlgDecl : public QDialog, public Ui::KPayeeReassignDlgDecl -{ -public: - KPayeeReassignDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; -class KPayeeReassignDlg : public KPayeeReassignDlgDecl +class KPayeeReassignDlgPrivate; +class KPayeeReassignDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KPayeeReassignDlg) + public: /** Change behavior based on type of operation */ enum OperationType { TypeMerge = 0, TypeDelete, TypeCount, }; /** Default constructor */ - KPayeeReassignDlg(OperationType type, QWidget* parent = 0); + KPayeeReassignDlg(OperationType type, QWidget* parent = nullptr); /** Destructor */ ~KPayeeReassignDlg(); /** * This function sets up the dialog, lets the user select a payee and returns * the id of the selected payee in the payeeslist. * * @param payeeslist reference to QList of MyMoneyPayee objects to be contained in the list * * @return Returns the id of the selected payee in the list or QString() if * the dialog was aborted. QString() is also returned if the payeeslist is empty. */ QString show(const QList& payeeslist); /** * Returns true, if the names of the payees to be deleted should be copied * to the selected payee's match list. */ - bool addToMatchList() const { - return m_copyToMatchList->isChecked(); - } + bool addToMatchList() const; protected: - void accept(); - -private: - OperationType m_type; + void accept() override; +private: + KPayeeReassignDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KPayeeReassignDlg) }; #endif // KPAYEEREASSIGNDLG_H diff --git a/kmymoney/dialogs/kpayeereassigndlgdecl.ui b/kmymoney/dialogs/kpayeereassigndlg.ui similarity index 95% rename from kmymoney/dialogs/kpayeereassigndlgdecl.ui rename to kmymoney/dialogs/kpayeereassigndlg.ui index cb9c08b44..6924cb0cd 100644 --- a/kmymoney/dialogs/kpayeereassigndlgdecl.ui +++ b/kmymoney/dialogs/kpayeereassigndlg.ui @@ -1,157 +1,157 @@ - KPayeeReassignDlgDecl - + KPayeeReassignDlg + 0 0 558 312 Reassign payees false true 300 0 Qt::AlignJustify|Qt::AlignTop true Qt::Vertical QSizePolicy::Fixed 20 16 Available payees: false Qt::Vertical QSizePolicy::Expanding 20 20 Assign deleted names to the above selected payee's matching list true QFrame::HLine QFrame::Sunken QDialogButtonBox::Cancel|QDialogButtonBox::Ok KMyMoneyPayeeCombo QWidget
kmymoneymvccombo.h
1
buttonBox accepted() - KPayeeReassignDlgDecl + KPayeeReassignDlg accept() 239 283 117 309 buttonBox rejected() - KPayeeReassignDlgDecl + KPayeeReassignDlg reject() 456 292 418 308
diff --git a/kmymoney/dialogs/kreportconfigurationfilterdlg.cpp b/kmymoney/dialogs/kreportconfigurationfilterdlg.cpp index 497f581e1..221b3232c 100644 --- a/kmymoney/dialogs/kreportconfigurationfilterdlg.cpp +++ b/kmymoney/dialogs/kreportconfigurationfilterdlg.cpp @@ -1,754 +1,798 @@ /*************************************************************************** kreportconfigurationdlg.cpp - description ------------------- begin : Mon Jun 21 2004 copyright : (C) 2000-2004 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio Ace Jones + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kreportconfigurationfilterdlg.h" +#include "kfindtransactiondlg_p.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include -#include -#include #include #include // ---------------------------------------------------------------------------- // Project Includes #include "kmymoneydateinput.h" #include "kmymoneyedit.h" #include "mymoneyfile.h" +#include "mymoneybudget.h" #include "mymoneyreport.h" #include "daterangedlg.h" #include "reporttabimpl.h" -#include "ui_kfindtransactiondlgdecl.h" +#include "ui_kfindtransactiondlg.h" #include #include #include #include #include #include #include -KReportConfigurationFilterDlg::KReportConfigurationFilterDlg(MyMoneyReport report, QWidget *parent) - : KFindTransactionDlg(parent, (report.rowType() == MyMoneyReport::eAccount)) - , m_tabRowColPivot(0) - , m_tabRowColQuery(0) - , m_tabChart(0) - , m_tabRange(0) - , m_initialState(report) - , m_currentState(report) +class KReportConfigurationFilterDlgPrivate : public KFindTransactionDlgPrivate { + Q_DISABLE_COPY(KReportConfigurationFilterDlgPrivate) + +public: + KReportConfigurationFilterDlgPrivate(KReportConfigurationFilterDlg *qq) : + KFindTransactionDlgPrivate(qq), + m_tabRowColPivot(nullptr), + m_tabRowColQuery(nullptr), + m_tabChart(nullptr), + m_tabRange(nullptr) + { + } + + QPointer m_tabGeneral; + QPointer m_tabRowColPivot; + QPointer m_tabRowColQuery; + QPointer m_tabChart; + QPointer m_tabRange; + QPointer m_tabCapitalGain; + QPointer m_tabPerformance; + + MyMoneyReport m_initialState; + MyMoneyReport m_currentState; + QVector m_budgets; +}; + +KReportConfigurationFilterDlg::KReportConfigurationFilterDlg(MyMoneyReport report, QWidget *parent) : + KFindTransactionDlg(*new KReportConfigurationFilterDlgPrivate(this), parent, (report.rowType() == MyMoneyReport::eAccount)) +{ + Q_D(KReportConfigurationFilterDlg); + + d->m_initialState = report; + d->m_currentState = report; + // // Rework labeling // setWindowTitle(i18n("Report Configuration")); - delete m_ui->TextLabel1; + delete d->ui->TextLabel1; // // Rework the buttons // // the Apply button is always enabled disconnect(SIGNAL(selectionNotEmpty(bool))); - m_ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); - KGuiItem::assign(m_ui->buttonBox->button(QDialogButtonBox::Apply), KStandardGuiItem::ok()); - m_ui->buttonBox->button(QDialogButtonBox::Apply)->setToolTip(i18nc("@info:tooltip for report configuration apply button", "Apply the configuration changes to the report")); + d->ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); + d->ui->buttonBox->button(QDialogButtonBox::Apply)->setToolTip(i18nc("@info:tooltip for report configuration apply button", "Apply the configuration changes to the report")); // // Add new tabs // - m_tabGeneral = new ReportTabGeneral(m_ui->m_criteriaTab); - m_ui->m_criteriaTab->insertTab(0, m_tabGeneral, i18nc("General tab", "General")); + d->m_tabGeneral = new ReportTabGeneral(d->ui->m_criteriaTab); + d->ui->m_criteriaTab->insertTab(0, d->m_tabGeneral, i18nc("General tab", "General")); - if (m_initialState.reportType() == MyMoneyReport::ePivotTable) { + if (d->m_initialState.reportType() == MyMoneyReport::ePivotTable) { int tabNr = 1; - if (!(m_initialState.isIncludingPrice() || m_initialState.isIncludingAveragePrice())) { - m_tabRowColPivot = new ReportTabRowColPivot(m_ui->m_criteriaTab); - m_ui->m_criteriaTab->insertTab(tabNr++, m_tabRowColPivot, i18n("Rows/Columns")); - connect(m_tabRowColPivot->ui->m_comboRows, SIGNAL(activated(int)), this, SLOT(slotRowTypeChanged(int))); - connect(m_tabRowColPivot->ui->m_comboRows, SIGNAL(activated(int)), this, SLOT(slotUpdateColumnsCombo())); + if (!(d->m_initialState.isIncludingPrice() || d->m_initialState.isIncludingAveragePrice())) { + d->m_tabRowColPivot = new ReportTabRowColPivot(d->ui->m_criteriaTab); + d->ui->m_criteriaTab->insertTab(tabNr++, d->m_tabRowColPivot, i18n("Rows/Columns")); + connect(d->m_tabRowColPivot->ui->m_comboRows, static_cast(&QComboBox::activated), this, static_cast(&KReportConfigurationFilterDlg::slotRowTypeChanged)); + connect(d->m_tabRowColPivot->ui->m_comboRows, static_cast(&QComboBox::activated), this, static_cast(&KReportConfigurationFilterDlg::slotUpdateColumnsCombo)); //control the state of the includeTransfer check - connect(m_ui->m_categoriesView, SIGNAL(stateChanged()), this, SLOT(slotUpdateCheckTransfers())); + connect(d->ui->m_categoriesView, &KMyMoneySelector::stateChanged, this, &KReportConfigurationFilterDlg::slotUpdateCheckTransfers); } - m_tabChart = new ReportTabChart(m_ui->m_criteriaTab); - m_ui->m_criteriaTab->insertTab(tabNr++, m_tabChart, i18n("Chart")); + d->m_tabChart = new ReportTabChart(d->ui->m_criteriaTab); + d->ui->m_criteriaTab->insertTab(tabNr++, d->m_tabChart, i18n("Chart")); - m_tabRange = new ReportTabRange(m_ui->m_criteriaTab); - m_ui->m_criteriaTab->insertTab(tabNr++, m_tabRange, i18n("Range")); + d->m_tabRange = new ReportTabRange(d->ui->m_criteriaTab); + d->ui->m_criteriaTab->insertTab(tabNr++, d->m_tabRange, i18n("Range")); // date tab is going to be replaced by range tab, so delete it - m_ui->dateRangeLayout->removeWidget(m_dateRange); - m_dateRange->deleteLater(); - m_ui->m_criteriaTab->removeTab(m_ui->m_criteriaTab->indexOf(m_ui->m_dateTab)); - m_ui->m_dateTab->deleteLater(); + d->ui->dateRangeLayout->removeWidget(d->m_dateRange); + d->m_dateRange->deleteLater(); + d->ui->m_criteriaTab->removeTab(d->ui->m_criteriaTab->indexOf(d->ui->m_dateTab)); + d->ui->m_dateTab->deleteLater(); - m_dateRange = m_tabRange->m_dateRange; + d->m_dateRange = d->m_tabRange->m_dateRange; // reconnect signal - connect(m_dateRange, SIGNAL(rangeChanged()), this, SLOT(slotUpdateSelections())); + connect(d->m_dateRange, &DateRangeDlg::rangeChanged, this, &KReportConfigurationFilterDlg::slotUpdateSelections); - if (!(m_initialState.isIncludingPrice() || m_initialState.isIncludingAveragePrice())) { - connect(m_tabRange->ui->m_comboColumns, SIGNAL(activated(int)), this, SLOT(slotColumnTypeChanged(int))); - connect(m_tabRange->ui->m_comboColumns, SIGNAL(activated(int)), this, SLOT(slotUpdateColumnsCombo())); + if (!(d->m_initialState.isIncludingPrice() || d->m_initialState.isIncludingAveragePrice())) { + connect(d->m_tabRange->ui->m_comboColumns, static_cast(&QComboBox::activated), this, &KReportConfigurationFilterDlg::slotColumnTypeChanged); + connect(d->m_tabRange->ui->m_comboColumns, static_cast(&QComboBox::activated), this, static_cast(&KReportConfigurationFilterDlg::slotUpdateColumnsCombo)); } - connect(m_tabChart->ui->m_logYaxis, SIGNAL(stateChanged(int)), this, SLOT(slotLogAxisChanged(int))); - } else if (m_initialState.reportType() == MyMoneyReport::eQueryTable) { + connect(d->m_tabChart->ui->m_logYaxis, &QCheckBox::stateChanged, this, &KReportConfigurationFilterDlg::slotLogAxisChanged); + } else if (d->m_initialState.reportType() == MyMoneyReport::eQueryTable) { // eInvestmentHoldings is a special-case report, and you cannot configure the // rows & columns of that report. - if (m_initialState.rowType() < MyMoneyReport::eAccountByTopAccount) { - m_tabRowColQuery = new ReportTabRowColQuery(m_ui->m_criteriaTab); - m_ui->m_criteriaTab->insertTab(1, m_tabRowColQuery, i18n("Rows/Columns")); + if (d->m_initialState.rowType() < MyMoneyReport::eAccountByTopAccount) { + d->m_tabRowColQuery = new ReportTabRowColQuery(d->ui->m_criteriaTab); + d->ui->m_criteriaTab->insertTab(1, d->m_tabRowColQuery, i18n("Rows/Columns")); } - if (m_initialState.queryColumns() & MyMoneyReport::eQCcapitalgain) { - m_tabCapitalGain = new ReportTabCapitalGain(m_ui->m_criteriaTab); - m_ui->m_criteriaTab->insertTab(1, m_tabCapitalGain, i18n("Report")); + if (d->m_initialState.queryColumns() & MyMoneyReport::eQCcapitalgain) { + d->m_tabCapitalGain = new ReportTabCapitalGain(d->ui->m_criteriaTab); + d->ui->m_criteriaTab->insertTab(1, d->m_tabCapitalGain, i18n("Report")); } - if (m_initialState.queryColumns() & MyMoneyReport::eQCperformance) { - m_tabPerformance = new ReportTabPerformance(m_ui->m_criteriaTab); - m_ui->m_criteriaTab->insertTab(1, m_tabPerformance, i18n("Report")); + if (d->m_initialState.queryColumns() & MyMoneyReport::eQCperformance) { + d->m_tabPerformance = new ReportTabPerformance(d->ui->m_criteriaTab); + d->ui->m_criteriaTab->insertTab(1, d->m_tabPerformance, i18n("Report")); } } - m_ui->m_criteriaTab->setCurrentIndex(m_ui->m_criteriaTab->indexOf(m_tabGeneral)); - m_ui->m_criteriaTab->setMinimumSize(500, 200); + d->ui->m_criteriaTab->setCurrentIndex(d->ui->m_criteriaTab->indexOf(d->m_tabGeneral)); + d->ui->m_criteriaTab->setMinimumSize(500, 200); QList list = MyMoneyFile::instance()->budgetList(); QList::const_iterator it_b; for (it_b = list.constBegin(); it_b != list.constEnd(); ++it_b) { - m_budgets.push_back(*it_b); + d->m_budgets.push_back(*it_b); } // // Now set up the widgets with proper values // slotReset(); } KReportConfigurationFilterDlg::~KReportConfigurationFilterDlg() { } +MyMoneyReport KReportConfigurationFilterDlg::getConfig() const +{ + Q_D(const KReportConfigurationFilterDlg); + return d->m_currentState; +} + void KReportConfigurationFilterDlg::slotSearch() { + Q_D(KReportConfigurationFilterDlg); // setup the filter from the dialog widgets - setupFilter(); + d->setupFilter(); // Copy the m_filter over to the filter part of m_currentConfig. - m_currentState.assignFilter(m_filter); + d->m_currentState.assignFilter(d->m_filter); // Then extract the report properties - m_currentState.setName(m_tabGeneral->ui->m_editName->text()); - m_currentState.setComment(m_tabGeneral->ui->m_editComment->text()); - m_currentState.setConvertCurrency(m_tabGeneral->ui->m_checkCurrency->isChecked()); - m_currentState.setFavorite(m_tabGeneral->ui->m_checkFavorite->isChecked()); - m_currentState.setSkipZero(m_tabGeneral->ui->m_skipZero->isChecked()); + d->m_currentState.setName(d->m_tabGeneral->ui->m_editName->text()); + d->m_currentState.setComment(d->m_tabGeneral->ui->m_editComment->text()); + d->m_currentState.setConvertCurrency(d->m_tabGeneral->ui->m_checkCurrency->isChecked()); + d->m_currentState.setFavorite(d->m_tabGeneral->ui->m_checkFavorite->isChecked()); + d->m_currentState.setSkipZero(d->m_tabGeneral->ui->m_skipZero->isChecked()); - if (m_tabRowColPivot) { + if (d->m_tabRowColPivot) { MyMoneyReport::EDetailLevel dl[4] = { MyMoneyReport::eDetailAll, MyMoneyReport::eDetailTop, MyMoneyReport::eDetailGroup, MyMoneyReport::eDetailTotal }; - m_currentState.setDetailLevel(dl[m_tabRowColPivot->ui->m_comboDetail->currentIndex()]); + d->m_currentState.setDetailLevel(dl[d->m_tabRowColPivot->ui->m_comboDetail->currentIndex()]); // modify the rowtype only if the widget is enabled - if (m_tabRowColPivot->ui->m_comboRows->isEnabled()) { + if (d->m_tabRowColPivot->ui->m_comboRows->isEnabled()) { MyMoneyReport::ERowType rt[2] = { MyMoneyReport::eExpenseIncome, MyMoneyReport::eAssetLiability }; - m_currentState.setRowType(rt[m_tabRowColPivot->ui->m_comboRows->currentIndex()]); + d->m_currentState.setRowType(rt[d->m_tabRowColPivot->ui->m_comboRows->currentIndex()]); } - m_currentState.setShowingRowTotals(false); - if (m_tabRowColPivot->ui->m_comboRows->currentIndex() == 0) - m_currentState.setShowingRowTotals(m_tabRowColPivot->ui->m_checkTotalColumn->isChecked()); + d->m_currentState.setShowingRowTotals(false); + if (d->m_tabRowColPivot->ui->m_comboRows->currentIndex() == 0) + d->m_currentState.setShowingRowTotals(d->m_tabRowColPivot->ui->m_checkTotalColumn->isChecked()); - m_currentState.setShowingColumnTotals(m_tabRowColPivot->ui->m_checkTotalRow->isChecked()); - m_currentState.setIncludingSchedules(m_tabRowColPivot->ui->m_checkScheduled->isChecked()); + d->m_currentState.setShowingColumnTotals(d->m_tabRowColPivot->ui->m_checkTotalRow->isChecked()); + d->m_currentState.setIncludingSchedules(d->m_tabRowColPivot->ui->m_checkScheduled->isChecked()); - m_currentState.setIncludingTransfers(m_tabRowColPivot->ui->m_checkTransfers->isChecked()); + d->m_currentState.setIncludingTransfers(d->m_tabRowColPivot->ui->m_checkTransfers->isChecked()); - m_currentState.setIncludingUnusedAccounts(m_tabRowColPivot->ui->m_checkUnused->isChecked()); + d->m_currentState.setIncludingUnusedAccounts(d->m_tabRowColPivot->ui->m_checkUnused->isChecked()); - if (m_tabRowColPivot->ui->m_comboBudget->isEnabled()) { - m_currentState.setBudget(m_budgets[m_tabRowColPivot->ui->m_comboBudget->currentItem()].id(), m_initialState.rowType() == MyMoneyReport::eBudgetActual); + if (d->m_tabRowColPivot->ui->m_comboBudget->isEnabled()) { + d->m_currentState.setBudget(d->m_budgets[d->m_tabRowColPivot->ui->m_comboBudget->currentItem()].id(), d->m_initialState.rowType() == MyMoneyReport::eBudgetActual); } else { - m_currentState.setBudget(QString(), false); + d->m_currentState.setBudget(QString(), false); } //set moving average days - if (m_tabRowColPivot->ui->m_movingAverageDays->isEnabled()) { - m_currentState.setMovingAverageDays(m_tabRowColPivot->ui->m_movingAverageDays->value()); + if (d->m_tabRowColPivot->ui->m_movingAverageDays->isEnabled()) { + d->m_currentState.setMovingAverageDays(d->m_tabRowColPivot->ui->m_movingAverageDays->value()); } - } else if (m_tabRowColQuery) { + } else if (d->m_tabRowColQuery) { MyMoneyReport::ERowType rtq[8] = { MyMoneyReport::eCategory, MyMoneyReport::eTopCategory, MyMoneyReport::eTag, MyMoneyReport::ePayee, MyMoneyReport::eAccount, MyMoneyReport::eTopAccount, MyMoneyReport::eMonth, MyMoneyReport::eWeek }; - m_currentState.setRowType(rtq[m_tabRowColQuery->ui->m_comboOrganizeBy->currentIndex()]); + d->m_currentState.setRowType(rtq[d->m_tabRowColQuery->ui->m_comboOrganizeBy->currentIndex()]); unsigned qc = MyMoneyReport::eQCnone; - if (m_currentState.queryColumns() & MyMoneyReport::eQCloan) + if (d->m_currentState.queryColumns() & MyMoneyReport::eQCloan) // once a loan report, always a loan report qc = MyMoneyReport::eQCloan; - if (m_tabRowColQuery->ui->m_checkNumber->isChecked()) + if (d->m_tabRowColQuery->ui->m_checkNumber->isChecked()) qc |= MyMoneyReport::eQCnumber; - if (m_tabRowColQuery->ui->m_checkPayee->isChecked()) + if (d->m_tabRowColQuery->ui->m_checkPayee->isChecked()) qc |= MyMoneyReport::eQCpayee; - if (m_tabRowColQuery->ui->m_checkTag->isChecked()) + if (d->m_tabRowColQuery->ui->m_checkTag->isChecked()) qc |= MyMoneyReport::eQCtag; - if (m_tabRowColQuery->ui->m_checkCategory->isChecked()) + if (d->m_tabRowColQuery->ui->m_checkCategory->isChecked()) qc |= MyMoneyReport::eQCcategory; - if (m_tabRowColQuery->ui->m_checkMemo->isChecked()) + if (d->m_tabRowColQuery->ui->m_checkMemo->isChecked()) qc |= MyMoneyReport::eQCmemo; - if (m_tabRowColQuery->ui->m_checkAccount->isChecked()) + if (d->m_tabRowColQuery->ui->m_checkAccount->isChecked()) qc |= MyMoneyReport::eQCaccount; - if (m_tabRowColQuery->ui->m_checkReconciled->isChecked()) + if (d->m_tabRowColQuery->ui->m_checkReconciled->isChecked()) qc |= MyMoneyReport::eQCreconciled; - if (m_tabRowColQuery->ui->m_checkAction->isChecked()) + if (d->m_tabRowColQuery->ui->m_checkAction->isChecked()) qc |= MyMoneyReport::eQCaction; - if (m_tabRowColQuery->ui->m_checkShares->isChecked()) + if (d->m_tabRowColQuery->ui->m_checkShares->isChecked()) qc |= MyMoneyReport::eQCshares; - if (m_tabRowColQuery->ui->m_checkPrice->isChecked()) + if (d->m_tabRowColQuery->ui->m_checkPrice->isChecked()) qc |= MyMoneyReport::eQCprice; - if (m_tabRowColQuery->ui->m_checkBalance->isChecked()) + if (d->m_tabRowColQuery->ui->m_checkBalance->isChecked()) qc |= MyMoneyReport::eQCbalance; - m_currentState.setQueryColumns(static_cast(qc)); + d->m_currentState.setQueryColumns(static_cast(qc)); - m_currentState.setTax(m_tabRowColQuery->ui->m_checkTax->isChecked()); - m_currentState.setInvestmentsOnly(m_tabRowColQuery->ui->m_checkInvestments->isChecked()); - m_currentState.setLoansOnly(m_tabRowColQuery->ui->m_checkLoans->isChecked()); + d->m_currentState.setTax(d->m_tabRowColQuery->ui->m_checkTax->isChecked()); + d->m_currentState.setInvestmentsOnly(d->m_tabRowColQuery->ui->m_checkInvestments->isChecked()); + d->m_currentState.setLoansOnly(d->m_tabRowColQuery->ui->m_checkLoans->isChecked()); - m_currentState.setDetailLevel(m_tabRowColQuery->ui->m_checkHideSplitDetails->isChecked() ? + d->m_currentState.setDetailLevel(d->m_tabRowColQuery->ui->m_checkHideSplitDetails->isChecked() ? MyMoneyReport::eDetailNone : MyMoneyReport::eDetailAll); - m_currentState.setHideTransactions(m_tabRowColQuery->ui->m_checkHideTransactions->isChecked()); - m_currentState.setShowingColumnTotals(!m_tabRowColQuery->ui->m_checkHideTotals->isChecked()); + d->m_currentState.setHideTransactions(d->m_tabRowColQuery->ui->m_checkHideTransactions->isChecked()); + d->m_currentState.setShowingColumnTotals(!d->m_tabRowColQuery->ui->m_checkHideTotals->isChecked()); } - if (m_tabChart) { + if (d->m_tabChart) { MyMoneyReport::EChartType ct[5] = { MyMoneyReport::eChartLine, MyMoneyReport::eChartBar, MyMoneyReport::eChartStackedBar, MyMoneyReport::eChartPie, MyMoneyReport::eChartRing }; - m_currentState.setChartType(ct[m_tabChart->ui->m_comboType->currentIndex()]); - - m_currentState.setChartCHGridLines(m_tabChart->ui->m_checkCHGridLines->isChecked()); - m_currentState.setChartSVGridLines(m_tabChart->ui->m_checkSVGridLines->isChecked()); - m_currentState.setChartDataLabels(m_tabChart->ui->m_checkValues->isChecked()); - m_currentState.setChartByDefault(m_tabChart->ui->m_checkShowChart->isChecked()); - m_currentState.setChartLineWidth(m_tabChart->ui->m_lineWidth->value()); - m_currentState.setLogYAxis(m_tabChart->ui->m_logYaxis->isChecked()); + d->m_currentState.setChartType(ct[d->m_tabChart->ui->m_comboType->currentIndex()]); + + d->m_currentState.setChartCHGridLines(d->m_tabChart->ui->m_checkCHGridLines->isChecked()); + d->m_currentState.setChartSVGridLines(d->m_tabChart->ui->m_checkSVGridLines->isChecked()); + d->m_currentState.setChartDataLabels(d->m_tabChart->ui->m_checkValues->isChecked()); + d->m_currentState.setChartByDefault(d->m_tabChart->ui->m_checkShowChart->isChecked()); + d->m_currentState.setChartLineWidth(d->m_tabChart->ui->m_lineWidth->value()); + d->m_currentState.setLogYAxis(d->m_tabChart->ui->m_logYaxis->isChecked()); } - if (m_tabRange) { - m_currentState.setDataRangeStart(m_tabRange->ui->m_dataRangeStart->text()); - m_currentState.setDataRangeEnd(m_tabRange->ui->m_dataRangeEnd->text()); - m_currentState.setDataMajorTick(m_tabRange->ui->m_dataMajorTick->text()); - m_currentState.setDataMinorTick(m_tabRange->ui->m_dataMinorTick->text()); - m_currentState.setYLabelsPrecision(m_tabRange->ui->m_yLabelsPrecision->value()); - m_currentState.setDataFilter((MyMoneyReport::dataOptionE)m_tabRange->ui->m_dataLock->currentIndex()); + if (d->m_tabRange) { + d->m_currentState.setDataRangeStart(d->m_tabRange->ui->m_dataRangeStart->text()); + d->m_currentState.setDataRangeEnd(d->m_tabRange->ui->m_dataRangeEnd->text()); + d->m_currentState.setDataMajorTick(d->m_tabRange->ui->m_dataMajorTick->text()); + d->m_currentState.setDataMinorTick(d->m_tabRange->ui->m_dataMinorTick->text()); + d->m_currentState.setYLabelsPrecision(d->m_tabRange->ui->m_yLabelsPrecision->value()); + d->m_currentState.setDataFilter((MyMoneyReport::dataOptionE)d->m_tabRange->ui->m_dataLock->currentIndex()); MyMoneyReport::EColumnType ct[6] = { MyMoneyReport::eDays, MyMoneyReport::eWeeks, MyMoneyReport::eMonths, MyMoneyReport::eBiMonths, MyMoneyReport::eQuarters, MyMoneyReport::eYears }; bool dy[6] = { true, true, false, false, false, false }; - m_currentState.setColumnType(ct[m_tabRange->ui->m_comboColumns->currentIndex()]); + d->m_currentState.setColumnType(ct[d->m_tabRange->ui->m_comboColumns->currentIndex()]); //TODO (Ace) This should be implicit in the call above. MMReport needs fixin' - m_currentState.setColumnsAreDays(dy[m_tabRange->ui->m_comboColumns->currentIndex()]); + d->m_currentState.setColumnsAreDays(dy[d->m_tabRange->ui->m_comboColumns->currentIndex()]); } // setup the date lock - eMyMoney::TransactionFilter::Date range = m_dateRange->dateRange(); - m_currentState.setDateFilter(range); - - if (m_tabCapitalGain) { - m_currentState.setTermSeparator(m_tabCapitalGain->ui->m_termSeparator->date()); - m_currentState.setShowSTLTCapitalGains(m_tabCapitalGain->ui->m_showSTLTCapitalGains->isChecked()); - m_currentState.setSettlementPeriod(m_tabCapitalGain->ui->m_settlementPeriod->value()); - m_currentState.setShowingColumnTotals(!m_tabCapitalGain->ui->m_checkHideTotals->isChecked()); - m_currentState.setInvestmentSum(static_cast(m_tabCapitalGain->ui->m_investmentSum->currentData().toInt())); + eMyMoney::TransactionFilter::Date range = d->m_dateRange->dateRange(); + d->m_currentState.setDateFilter(range); + + if (d->m_tabCapitalGain) { + d->m_currentState.setTermSeparator(d->m_tabCapitalGain->ui->m_termSeparator->date()); + d->m_currentState.setShowSTLTCapitalGains(d->m_tabCapitalGain->ui->m_showSTLTCapitalGains->isChecked()); + d->m_currentState.setSettlementPeriod(d->m_tabCapitalGain->ui->m_settlementPeriod->value()); + d->m_currentState.setShowingColumnTotals(!d->m_tabCapitalGain->ui->m_checkHideTotals->isChecked()); + d->m_currentState.setInvestmentSum(static_cast(d->m_tabCapitalGain->ui->m_investmentSum->currentData().toInt())); } - if (m_tabPerformance) { - m_currentState.setShowingColumnTotals(!m_tabPerformance->ui->m_checkHideTotals->isChecked()); - m_currentState.setInvestmentSum(static_cast(m_tabPerformance->ui->m_investmentSum->currentData().toInt())); + if (d->m_tabPerformance) { + d->m_currentState.setShowingColumnTotals(!d->m_tabPerformance->ui->m_checkHideTotals->isChecked()); + d->m_currentState.setInvestmentSum(static_cast(d->m_tabPerformance->ui->m_investmentSum->currentData().toInt())); } done(true); } void KReportConfigurationFilterDlg::slotRowTypeChanged(int row) { - m_tabRowColPivot->ui->m_checkTotalColumn->setEnabled(row == 0); + Q_D(KReportConfigurationFilterDlg); + d->m_tabRowColPivot->ui->m_checkTotalColumn->setEnabled(row == 0); } void KReportConfigurationFilterDlg::slotColumnTypeChanged(int row) { - if ((m_tabRowColPivot->ui->m_comboBudget->isEnabled() && row < 2)) { - m_tabRange->ui->m_comboColumns->setCurrentItem(i18nc("@item the columns will display monthly data", "Monthly"), false); + Q_D(KReportConfigurationFilterDlg); + if ((d->m_tabRowColPivot->ui->m_comboBudget->isEnabled() && row < 2)) { + d->m_tabRange->ui->m_comboColumns->setCurrentItem(i18nc("@item the columns will display monthly data", "Monthly"), false); } } void KReportConfigurationFilterDlg::slotUpdateColumnsCombo() { + Q_D(KReportConfigurationFilterDlg); const int monthlyIndex = 2; const int incomeExpenseIndex = 0; - const bool isIncomeExpenseForecast = m_currentState.isIncludingForecast() && m_tabRowColPivot->ui->m_comboRows->currentIndex() == incomeExpenseIndex; - if (isIncomeExpenseForecast && m_tabRange->ui->m_comboColumns->currentIndex() != monthlyIndex) { - m_tabRange->ui->m_comboColumns->setCurrentItem(i18nc("@item the columns will display monthly data", "Monthly"), false); + const bool isIncomeExpenseForecast = d->m_currentState.isIncludingForecast() && d->m_tabRowColPivot->ui->m_comboRows->currentIndex() == incomeExpenseIndex; + if (isIncomeExpenseForecast && d->m_tabRange->ui->m_comboColumns->currentIndex() != monthlyIndex) { + d->m_tabRange->ui->m_comboColumns->setCurrentItem(i18nc("@item the columns will display monthly data", "Monthly"), false); } } +void KReportConfigurationFilterDlg::slotUpdateColumnsCombo(int) +{ + slotUpdateColumnsCombo(); +} + void KReportConfigurationFilterDlg::slotLogAxisChanged(int state) { + Q_D(KReportConfigurationFilterDlg); if (state == Qt::Checked) - m_tabRange->setRangeLogarythmic(true); + d->m_tabRange->setRangeLogarythmic(true); else - m_tabRange->setRangeLogarythmic(false); + d->m_tabRange->setRangeLogarythmic(false); } void KReportConfigurationFilterDlg::slotReset() { + Q_D(KReportConfigurationFilterDlg); // // Set up the widget from the initial filter // - m_currentState = m_initialState; + d->m_currentState = d->m_initialState; // // Report Properties // - m_tabGeneral->ui->m_editName->setText(m_initialState.name()); - m_tabGeneral->ui->m_editComment->setText(m_initialState.comment()); - m_tabGeneral->ui->m_checkCurrency->setChecked(m_initialState.isConvertCurrency()); - m_tabGeneral->ui->m_checkFavorite->setChecked(m_initialState.isFavorite()); + d->m_tabGeneral->ui->m_editName->setText(d->m_initialState.name()); + d->m_tabGeneral->ui->m_editComment->setText(d->m_initialState.comment()); + d->m_tabGeneral->ui->m_checkCurrency->setChecked(d->m_initialState.isConvertCurrency()); + d->m_tabGeneral->ui->m_checkFavorite->setChecked(d->m_initialState.isFavorite()); - if (m_initialState.isIncludingPrice() || m_initialState.isSkippingZero()) { - m_tabGeneral->ui->m_skipZero->setChecked(m_initialState.isSkippingZero()); + if (d->m_initialState.isIncludingPrice() || d->m_initialState.isSkippingZero()) { + d->m_tabGeneral->ui->m_skipZero->setChecked(d->m_initialState.isSkippingZero()); } else { - m_tabGeneral->ui->m_skipZero->setEnabled(false); + d->m_tabGeneral->ui->m_skipZero->setEnabled(false); } - if (m_tabRowColPivot) { - KComboBox *combo = m_tabRowColPivot->ui->m_comboDetail; - switch (m_initialState.detailLevel()) { + if (d->m_tabRowColPivot) { + KComboBox *combo = d->m_tabRowColPivot->ui->m_comboDetail; + switch (d->m_initialState.detailLevel()) { case MyMoneyReport::eDetailNone: case MyMoneyReport::eDetailEnd: case MyMoneyReport::eDetailAll: combo->setCurrentItem(i18nc("All accounts", "All"), false); break; case MyMoneyReport::eDetailTop: combo->setCurrentItem(i18n("Top-Level"), false); break; case MyMoneyReport::eDetailGroup: combo->setCurrentItem(i18n("Groups"), false); break; case MyMoneyReport::eDetailTotal: combo->setCurrentItem(i18n("Totals"), false); break; } - combo = m_tabRowColPivot->ui->m_comboRows; - switch (m_initialState.rowType()) { + combo = d->m_tabRowColPivot->ui->m_comboRows; + switch (d->m_initialState.rowType()) { case MyMoneyReport::eExpenseIncome: case MyMoneyReport::eBudget: case MyMoneyReport::eBudgetActual: combo->setCurrentItem(i18n("Income & Expenses"), false); // income / expense break; default: combo->setCurrentItem(i18n("Assets & Liabilities"), false); // asset / liability break; } - m_tabRowColPivot->ui->m_checkTotalColumn->setChecked(m_initialState.isShowingRowTotals()); - m_tabRowColPivot->ui->m_checkTotalRow->setChecked(m_initialState.isShowingColumnTotals()); + d->m_tabRowColPivot->ui->m_checkTotalColumn->setChecked(d->m_initialState.isShowingRowTotals()); + d->m_tabRowColPivot->ui->m_checkTotalRow->setChecked(d->m_initialState.isShowingColumnTotals()); slotRowTypeChanged(combo->currentIndex()); //load budgets combo - if (m_initialState.rowType() == MyMoneyReport::eBudget - || m_initialState.rowType() == MyMoneyReport::eBudgetActual) { - m_tabRowColPivot->ui->m_comboRows->setEnabled(false); - m_tabRowColPivot->ui->m_budgetFrame->setEnabled(!m_budgets.empty()); - int i = 0; - for (QVector::const_iterator it_b = m_budgets.constBegin(); it_b != m_budgets.constEnd(); ++it_b) { - m_tabRowColPivot->ui->m_comboBudget->insertItem((*it_b).name(), i); + if (d->m_initialState.rowType() == MyMoneyReport::eBudget + || d->m_initialState.rowType() == MyMoneyReport::eBudgetActual) { + d->m_tabRowColPivot->ui->m_comboRows->setEnabled(false); + d->m_tabRowColPivot->ui->m_budgetFrame->setEnabled(!d->m_budgets.empty()); + auto i = 0; + for (QVector::const_iterator it_b = d->m_budgets.constBegin(); it_b != d->m_budgets.constEnd(); ++it_b) { + d->m_tabRowColPivot->ui->m_comboBudget->insertItem((*it_b).name(), i); //set the current selected item - if ((m_initialState.budget() == "Any" && (*it_b).budgetStart().year() == QDate::currentDate().year()) - || m_initialState.budget() == (*it_b).id()) - m_tabRowColPivot->ui->m_comboBudget->setCurrentItem(i); + if ((d->m_initialState.budget() == "Any" && (*it_b).budgetStart().year() == QDate::currentDate().year()) + || d->m_initialState.budget() == (*it_b).id()) + d->m_tabRowColPivot->ui->m_comboBudget->setCurrentItem(i); i++; } } //set moving average days spinbox - QSpinBox *spinbox = m_tabRowColPivot->ui->m_movingAverageDays; - spinbox->setEnabled(m_initialState.isIncludingMovingAverage()); - if (m_initialState.isIncludingMovingAverage()) { - spinbox->setValue(m_initialState.movingAverageDays()); + QSpinBox *spinbox = d->m_tabRowColPivot->ui->m_movingAverageDays; + spinbox->setEnabled(d->m_initialState.isIncludingMovingAverage()); + if (d->m_initialState.isIncludingMovingAverage()) { + spinbox->setValue(d->m_initialState.movingAverageDays()); } - m_tabRowColPivot->ui->m_checkScheduled->setChecked(m_initialState.isIncludingSchedules()); - m_tabRowColPivot->ui->m_checkTransfers->setChecked(m_initialState.isIncludingTransfers()); - m_tabRowColPivot->ui->m_checkUnused->setChecked(m_initialState.isIncludingUnusedAccounts()); - } else if (m_tabRowColQuery) { - KComboBox *combo = m_tabRowColQuery->ui->m_comboOrganizeBy; - switch (m_initialState.rowType()) { + d->m_tabRowColPivot->ui->m_checkScheduled->setChecked(d->m_initialState.isIncludingSchedules()); + d->m_tabRowColPivot->ui->m_checkTransfers->setChecked(d->m_initialState.isIncludingTransfers()); + d->m_tabRowColPivot->ui->m_checkUnused->setChecked(d->m_initialState.isIncludingUnusedAccounts()); + } else if (d->m_tabRowColQuery) { + KComboBox *combo = d->m_tabRowColQuery->ui->m_comboOrganizeBy; + switch (d->m_initialState.rowType()) { case MyMoneyReport::eNoColumns: case MyMoneyReport::eCategory: combo->setCurrentItem(i18n("Categories"), false); break; case MyMoneyReport::eTopCategory: combo->setCurrentItem(i18n("Top Categories"), false); break; case MyMoneyReport::eTag: combo->setCurrentItem(i18n("Tags"), false); break; case MyMoneyReport::ePayee: combo->setCurrentItem(i18n("Payees"), false); break; case MyMoneyReport::eAccount: combo->setCurrentItem(i18n("Accounts"), false); break; case MyMoneyReport::eTopAccount: combo->setCurrentItem(i18n("Top Accounts"), false); break; case MyMoneyReport::eMonth: combo->setCurrentItem(i18n("Month"), false); break; case MyMoneyReport::eWeek: combo->setCurrentItem(i18n("Week"), false); break; default: throw MYMONEYEXCEPTION("KReportConfigurationFilterDlg::slotReset(): QueryTable report has invalid rowtype"); } - unsigned qc = m_initialState.queryColumns(); - m_tabRowColQuery->ui->m_checkNumber->setChecked(qc & MyMoneyReport::eQCnumber); - m_tabRowColQuery->ui->m_checkPayee->setChecked(qc & MyMoneyReport::eQCpayee); - m_tabRowColQuery->ui->m_checkTag->setChecked(qc & MyMoneyReport::eQCtag); - m_tabRowColQuery->ui->m_checkCategory->setChecked(qc & MyMoneyReport::eQCcategory); - m_tabRowColQuery->ui->m_checkMemo->setChecked(qc & MyMoneyReport::eQCmemo); - m_tabRowColQuery->ui->m_checkAccount->setChecked(qc & MyMoneyReport::eQCaccount); - m_tabRowColQuery->ui->m_checkReconciled->setChecked(qc & MyMoneyReport::eQCreconciled); - m_tabRowColQuery->ui->m_checkAction->setChecked(qc & MyMoneyReport::eQCaction); - m_tabRowColQuery->ui->m_checkShares->setChecked(qc & MyMoneyReport::eQCshares); - m_tabRowColQuery->ui->m_checkPrice->setChecked(qc & MyMoneyReport::eQCprice); - m_tabRowColQuery->ui->m_checkBalance->setChecked(qc & MyMoneyReport::eQCbalance); - - m_tabRowColQuery->ui->m_checkTax->setChecked(m_initialState.isTax()); - m_tabRowColQuery->ui->m_checkInvestments->setChecked(m_initialState.isInvestmentsOnly()); - m_tabRowColQuery->ui->m_checkLoans->setChecked(m_initialState.isLoansOnly()); - - m_tabRowColQuery->ui->m_checkHideTransactions->setChecked(m_initialState.isHideTransactions()); - m_tabRowColQuery->ui->m_checkHideTotals->setChecked(!m_initialState.isShowingColumnTotals()); - m_tabRowColQuery->ui->m_checkHideSplitDetails->setEnabled(!m_initialState.isHideTransactions()); - - m_tabRowColQuery->ui->m_checkHideSplitDetails->setChecked - (m_initialState.detailLevel() == MyMoneyReport::eDetailNone || m_initialState.isHideTransactions()); + unsigned qc = d->m_initialState.queryColumns(); + d->m_tabRowColQuery->ui->m_checkNumber->setChecked(qc & MyMoneyReport::eQCnumber); + d->m_tabRowColQuery->ui->m_checkPayee->setChecked(qc & MyMoneyReport::eQCpayee); + d->m_tabRowColQuery->ui->m_checkTag->setChecked(qc & MyMoneyReport::eQCtag); + d->m_tabRowColQuery->ui->m_checkCategory->setChecked(qc & MyMoneyReport::eQCcategory); + d->m_tabRowColQuery->ui->m_checkMemo->setChecked(qc & MyMoneyReport::eQCmemo); + d->m_tabRowColQuery->ui->m_checkAccount->setChecked(qc & MyMoneyReport::eQCaccount); + d->m_tabRowColQuery->ui->m_checkReconciled->setChecked(qc & MyMoneyReport::eQCreconciled); + d->m_tabRowColQuery->ui->m_checkAction->setChecked(qc & MyMoneyReport::eQCaction); + d->m_tabRowColQuery->ui->m_checkShares->setChecked(qc & MyMoneyReport::eQCshares); + d->m_tabRowColQuery->ui->m_checkPrice->setChecked(qc & MyMoneyReport::eQCprice); + d->m_tabRowColQuery->ui->m_checkBalance->setChecked(qc & MyMoneyReport::eQCbalance); + + d->m_tabRowColQuery->ui->m_checkTax->setChecked(d->m_initialState.isTax()); + d->m_tabRowColQuery->ui->m_checkInvestments->setChecked(d->m_initialState.isInvestmentsOnly()); + d->m_tabRowColQuery->ui->m_checkLoans->setChecked(d->m_initialState.isLoansOnly()); + + d->m_tabRowColQuery->ui->m_checkHideTransactions->setChecked(d->m_initialState.isHideTransactions()); + d->m_tabRowColQuery->ui->m_checkHideTotals->setChecked(!d->m_initialState.isShowingColumnTotals()); + d->m_tabRowColQuery->ui->m_checkHideSplitDetails->setEnabled(!d->m_initialState.isHideTransactions()); + + d->m_tabRowColQuery->ui->m_checkHideSplitDetails->setChecked + (d->m_initialState.detailLevel() == MyMoneyReport::eDetailNone || d->m_initialState.isHideTransactions()); } - if (m_tabChart) { - KMyMoneyGeneralCombo* combo = m_tabChart->ui->m_comboType; - switch (m_initialState.chartType()) { + if (d->m_tabChart) { + KMyMoneyGeneralCombo* combo = d->m_tabChart->ui->m_comboType; + switch (d->m_initialState.chartType()) { case MyMoneyReport::eChartNone: combo->setCurrentItem(MyMoneyReport::eChartLine); break; case MyMoneyReport::eChartLine: case MyMoneyReport::eChartBar: case MyMoneyReport::eChartStackedBar: case MyMoneyReport::eChartPie: case MyMoneyReport::eChartRing: - combo->setCurrentItem(m_initialState.chartType()); + combo->setCurrentItem(d->m_initialState.chartType()); break; default: throw MYMONEYEXCEPTION("KReportConfigurationFilterDlg::slotReset(): Report has invalid charttype"); } - m_tabChart->ui->m_checkCHGridLines->setChecked(m_initialState.isChartCHGridLines()); - m_tabChart->ui->m_checkSVGridLines->setChecked(m_initialState.isChartSVGridLines()); - m_tabChart->ui->m_checkValues->setChecked(m_initialState.isChartDataLabels()); - m_tabChart->ui->m_checkShowChart->setChecked(m_initialState.isChartByDefault()); - m_tabChart->ui->m_lineWidth->setValue(m_initialState.chartLineWidth()); - m_tabChart->ui->m_logYaxis->setChecked(m_initialState.isLogYAxis()); + d->m_tabChart->ui->m_checkCHGridLines->setChecked(d->m_initialState.isChartCHGridLines()); + d->m_tabChart->ui->m_checkSVGridLines->setChecked(d->m_initialState.isChartSVGridLines()); + d->m_tabChart->ui->m_checkValues->setChecked(d->m_initialState.isChartDataLabels()); + d->m_tabChart->ui->m_checkShowChart->setChecked(d->m_initialState.isChartByDefault()); + d->m_tabChart->ui->m_lineWidth->setValue(d->m_initialState.chartLineWidth()); + d->m_tabChart->ui->m_logYaxis->setChecked(d->m_initialState.isLogYAxis()); } - if (m_tabRange) { - m_tabRange->ui->m_dataRangeStart->setText(m_initialState.dataRangeStart()); - m_tabRange->ui->m_dataRangeEnd->setText(m_initialState.dataRangeEnd()); - m_tabRange->ui->m_dataMajorTick->setText(m_initialState.dataMajorTick()); - m_tabRange->ui->m_dataMinorTick->setText(m_initialState.dataMinorTick()); - m_tabRange->ui->m_yLabelsPrecision->setValue(m_initialState.yLabelsPrecision()); - m_tabRange->ui->m_dataLock->setCurrentIndex((int)m_initialState.dataFilter()); - - KComboBox *combo = m_tabRange->ui->m_comboColumns; - if (m_initialState.isColumnsAreDays()) { - switch (m_initialState.columnType()) { + if (d->m_tabRange) { + d->m_tabRange->ui->m_dataRangeStart->setText(d->m_initialState.dataRangeStart()); + d->m_tabRange->ui->m_dataRangeEnd->setText(d->m_initialState.dataRangeEnd()); + d->m_tabRange->ui->m_dataMajorTick->setText(d->m_initialState.dataMajorTick()); + d->m_tabRange->ui->m_dataMinorTick->setText(d->m_initialState.dataMinorTick()); + d->m_tabRange->ui->m_yLabelsPrecision->setValue(d->m_initialState.yLabelsPrecision()); + d->m_tabRange->ui->m_dataLock->setCurrentIndex((int)d->m_initialState.dataFilter()); + + KComboBox *combo = d->m_tabRange->ui->m_comboColumns; + if (d->m_initialState.isColumnsAreDays()) { + switch (d->m_initialState.columnType()) { case MyMoneyReport::eNoColumns: case MyMoneyReport::eDays: combo->setCurrentItem(i18nc("@item the columns will display daily data", "Daily"), false); break; case MyMoneyReport::eWeeks: combo->setCurrentItem(i18nc("@item the columns will display weekly data", "Weekly"), false); break; default: break; } } else { - switch (m_initialState.columnType()) { + switch (d->m_initialState.columnType()) { case MyMoneyReport::eNoColumns: case MyMoneyReport::eMonths: combo->setCurrentItem(i18nc("@item the columns will display monthly data", "Monthly"), false); break; case MyMoneyReport::eBiMonths: combo->setCurrentItem(i18nc("@item the columns will display bi-monthly data", "Bi-Monthly"), false); break; case MyMoneyReport::eQuarters: combo->setCurrentItem(i18nc("@item the columns will display quarterly data", "Quarterly"), false); break; case MyMoneyReport::eYears: combo->setCurrentItem(i18nc("@item the columns will display yearly data", "Yearly"), false); break; default: break; } } } - if (m_tabCapitalGain) { - m_tabCapitalGain->ui->m_termSeparator->setDate(m_initialState.termSeparator()); - m_tabCapitalGain->ui->m_showSTLTCapitalGains->setChecked(m_initialState.isShowingSTLTCapitalGains()); - m_tabCapitalGain->ui->m_settlementPeriod->setValue(m_initialState.settlementPeriod()); - m_tabCapitalGain->ui->m_checkHideTotals->setChecked(!m_initialState.isShowingColumnTotals()); - m_tabCapitalGain->ui->m_investmentSum->blockSignals(true); - m_tabCapitalGain->ui->m_investmentSum->clear(); - m_tabCapitalGain->ui->m_investmentSum->addItem(i18n("Only owned"), MyMoneyReport::eSumOwned); - m_tabCapitalGain->ui->m_investmentSum->addItem(i18n("Only sold"), MyMoneyReport::eSumSold); - m_tabCapitalGain->ui->m_investmentSum->blockSignals(false); - m_tabCapitalGain->ui->m_investmentSum->setCurrentIndex(m_tabCapitalGain->ui->m_investmentSum->findData(m_initialState.investmentSum())); + if (d->m_tabCapitalGain) { + d->m_tabCapitalGain->ui->m_termSeparator->setDate(d->m_initialState.termSeparator()); + d->m_tabCapitalGain->ui->m_showSTLTCapitalGains->setChecked(d->m_initialState.isShowingSTLTCapitalGains()); + d->m_tabCapitalGain->ui->m_settlementPeriod->setValue(d->m_initialState.settlementPeriod()); + d->m_tabCapitalGain->ui->m_checkHideTotals->setChecked(!d->m_initialState.isShowingColumnTotals()); + d->m_tabCapitalGain->ui->m_investmentSum->blockSignals(true); + d->m_tabCapitalGain->ui->m_investmentSum->clear(); + d->m_tabCapitalGain->ui->m_investmentSum->addItem(i18n("Only owned"), MyMoneyReport::eSumOwned); + d->m_tabCapitalGain->ui->m_investmentSum->addItem(i18n("Only sold"), MyMoneyReport::eSumSold); + d->m_tabCapitalGain->ui->m_investmentSum->blockSignals(false); + d->m_tabCapitalGain->ui->m_investmentSum->setCurrentIndex(d->m_tabCapitalGain->ui->m_investmentSum->findData(d->m_initialState.investmentSum())); } - if (m_tabPerformance) { - m_tabPerformance->ui->m_checkHideTotals->setChecked(!m_initialState.isShowingColumnTotals()); - m_tabPerformance->ui->m_investmentSum->blockSignals(true); - m_tabPerformance->ui->m_investmentSum->clear(); - m_tabPerformance->ui->m_investmentSum->addItem(i18n("From period"), MyMoneyReport::eSumPeriod); - m_tabPerformance->ui->m_investmentSum->addItem(i18n("Owned and sold"), MyMoneyReport::eSumOwnedAndSold); - m_tabPerformance->ui->m_investmentSum->addItem(i18n("Only owned"), MyMoneyReport::eSumOwned); - m_tabPerformance->ui->m_investmentSum->addItem(i18n("Only sold"), MyMoneyReport::eSumSold); - m_tabPerformance->ui->m_investmentSum->blockSignals(false); - m_tabPerformance->ui->m_investmentSum->setCurrentIndex(m_tabPerformance->ui->m_investmentSum->findData(m_initialState.investmentSum())); + if (d->m_tabPerformance) { + d->m_tabPerformance->ui->m_checkHideTotals->setChecked(!d->m_initialState.isShowingColumnTotals()); + d->m_tabPerformance->ui->m_investmentSum->blockSignals(true); + d->m_tabPerformance->ui->m_investmentSum->clear(); + d->m_tabPerformance->ui->m_investmentSum->addItem(i18n("From period"), MyMoneyReport::eSumPeriod); + d->m_tabPerformance->ui->m_investmentSum->addItem(i18n("Owned and sold"), MyMoneyReport::eSumOwnedAndSold); + d->m_tabPerformance->ui->m_investmentSum->addItem(i18n("Only owned"), MyMoneyReport::eSumOwned); + d->m_tabPerformance->ui->m_investmentSum->addItem(i18n("Only sold"), MyMoneyReport::eSumSold); + d->m_tabPerformance->ui->m_investmentSum->blockSignals(false); + d->m_tabPerformance->ui->m_investmentSum->setCurrentIndex(d->m_tabPerformance->ui->m_investmentSum->findData(d->m_initialState.investmentSum())); } // // Text Filter // QRegExp textfilter; - if (m_initialState.textFilter(textfilter)) { - m_ui->m_textEdit->setText(textfilter.pattern()); - m_ui->m_caseSensitive->setChecked(Qt::CaseSensitive == textfilter.caseSensitivity()); - m_ui->m_regExp->setChecked(QRegExp::RegExp == textfilter.patternSyntax()); - m_ui->m_textNegate->setCurrentIndex(m_initialState.isInvertingText()); + if (d->m_initialState.textFilter(textfilter)) { + d->ui->m_textEdit->setText(textfilter.pattern()); + d->ui->m_caseSensitive->setChecked(Qt::CaseSensitive == textfilter.caseSensitivity()); + d->ui->m_regExp->setChecked(QRegExp::RegExp == textfilter.patternSyntax()); + d->ui->m_textNegate->setCurrentIndex(d->m_initialState.isInvertingText()); } // // Type & State Filters // int type; - if (m_initialState.firstType(type)) - m_ui->m_typeBox->setCurrentIndex(type); + if (d->m_initialState.firstType(type)) + d->ui->m_typeBox->setCurrentIndex(type); int state; - if (m_initialState.firstState(state)) - m_ui->m_stateBox->setCurrentIndex(state); + if (d->m_initialState.firstState(state)) + d->ui->m_stateBox->setCurrentIndex(state); // // Number Filter // QString nrFrom, nrTo; - if (m_initialState.numberFilter(nrFrom, nrTo)) { + if (d->m_initialState.numberFilter(nrFrom, nrTo)) { if (nrFrom == nrTo) { - m_ui->m_nrEdit->setEnabled(true); - m_ui->m_nrFromEdit->setEnabled(false); - m_ui->m_nrToEdit->setEnabled(false); - m_ui->m_nrEdit->setText(nrFrom); - m_ui->m_nrFromEdit->setText(QString()); - m_ui->m_nrToEdit->setText(QString()); - m_ui->m_nrButton->setChecked(true); - m_ui->m_nrRangeButton->setChecked(false); + d->ui->m_nrEdit->setEnabled(true); + d->ui->m_nrFromEdit->setEnabled(false); + d->ui->m_nrToEdit->setEnabled(false); + d->ui->m_nrEdit->setText(nrFrom); + d->ui->m_nrFromEdit->setText(QString()); + d->ui->m_nrToEdit->setText(QString()); + d->ui->m_nrButton->setChecked(true); + d->ui->m_nrRangeButton->setChecked(false); } else { - m_ui->m_nrEdit->setEnabled(false); - m_ui->m_nrFromEdit->setEnabled(true); - m_ui->m_nrToEdit->setEnabled(false); - m_ui->m_nrEdit->setText(QString()); - m_ui->m_nrFromEdit->setText(nrFrom); - m_ui->m_nrToEdit->setText(nrTo); - m_ui->m_nrButton->setChecked(false); - m_ui->m_nrRangeButton->setChecked(true); + d->ui->m_nrEdit->setEnabled(false); + d->ui->m_nrFromEdit->setEnabled(true); + d->ui->m_nrToEdit->setEnabled(false); + d->ui->m_nrEdit->setText(QString()); + d->ui->m_nrFromEdit->setText(nrFrom); + d->ui->m_nrToEdit->setText(nrTo); + d->ui->m_nrButton->setChecked(false); + d->ui->m_nrRangeButton->setChecked(true); } } else { - m_ui->m_nrEdit->setEnabled(true); - m_ui->m_nrFromEdit->setEnabled(false); - m_ui->m_nrToEdit->setEnabled(false); - m_ui->m_nrEdit->setText(QString()); - m_ui->m_nrFromEdit->setText(QString()); - m_ui->m_nrToEdit->setText(QString()); - m_ui->m_nrButton->setChecked(true); - m_ui->m_nrRangeButton->setChecked(false); + d->ui->m_nrEdit->setEnabled(true); + d->ui->m_nrFromEdit->setEnabled(false); + d->ui->m_nrToEdit->setEnabled(false); + d->ui->m_nrEdit->setText(QString()); + d->ui->m_nrFromEdit->setText(QString()); + d->ui->m_nrToEdit->setText(QString()); + d->ui->m_nrButton->setChecked(true); + d->ui->m_nrRangeButton->setChecked(false); } // // Amount Filter // MyMoneyMoney from, to; - if (m_initialState.amountFilter(from, to)) { // bool getAmountFilter(MyMoneyMoney&,MyMoneyMoney&); + if (d->m_initialState.amountFilter(from, to)) { // bool getAmountFilter(MyMoneyMoney&,MyMoneyMoney&); if (from == to) { - m_ui->m_amountEdit->setEnabled(true); - m_ui->m_amountFromEdit->setEnabled(false); - m_ui->m_amountToEdit->setEnabled(false); - m_ui->m_amountEdit->loadText(QString::number(from.toDouble())); - m_ui->m_amountFromEdit->loadText(QString()); - m_ui->m_amountToEdit->loadText(QString()); - m_ui->m_amountButton->setChecked(true); - m_ui->m_amountRangeButton->setChecked(false); + d->ui->m_amountEdit->setEnabled(true); + d->ui->m_amountFromEdit->setEnabled(false); + d->ui->m_amountToEdit->setEnabled(false); + d->ui->m_amountEdit->loadText(QString::number(from.toDouble())); + d->ui->m_amountFromEdit->loadText(QString()); + d->ui->m_amountToEdit->loadText(QString()); + d->ui->m_amountButton->setChecked(true); + d->ui->m_amountRangeButton->setChecked(false); } else { - m_ui->m_amountEdit->setEnabled(false); - m_ui->m_amountFromEdit->setEnabled(true); - m_ui->m_amountToEdit->setEnabled(true); - m_ui->m_amountEdit->loadText(QString()); - m_ui->m_amountFromEdit->loadText(QString::number(from.toDouble())); - m_ui->m_amountToEdit->loadText(QString::number(to.toDouble())); - m_ui->m_amountButton->setChecked(false); - m_ui->m_amountRangeButton->setChecked(true); + d->ui->m_amountEdit->setEnabled(false); + d->ui->m_amountFromEdit->setEnabled(true); + d->ui->m_amountToEdit->setEnabled(true); + d->ui->m_amountEdit->loadText(QString()); + d->ui->m_amountFromEdit->loadText(QString::number(from.toDouble())); + d->ui->m_amountToEdit->loadText(QString::number(to.toDouble())); + d->ui->m_amountButton->setChecked(false); + d->ui->m_amountRangeButton->setChecked(true); } } else { - m_ui->m_amountEdit->setEnabled(true); - m_ui->m_amountFromEdit->setEnabled(false); - m_ui->m_amountToEdit->setEnabled(false); - m_ui->m_amountEdit->loadText(QString()); - m_ui->m_amountFromEdit->loadText(QString()); - m_ui->m_amountToEdit->loadText(QString()); - m_ui->m_amountButton->setChecked(true); - m_ui->m_amountRangeButton->setChecked(false); + d->ui->m_amountEdit->setEnabled(true); + d->ui->m_amountFromEdit->setEnabled(false); + d->ui->m_amountToEdit->setEnabled(false); + d->ui->m_amountEdit->loadText(QString()); + d->ui->m_amountFromEdit->loadText(QString()); + d->ui->m_amountToEdit->loadText(QString()); + d->ui->m_amountButton->setChecked(true); + d->ui->m_amountRangeButton->setChecked(false); } // // Payees Filter // QStringList payees; - if (m_initialState.payees(payees)) { + if (d->m_initialState.payees(payees)) { if (payees.empty()) { - m_ui->m_emptyPayeesButton->setChecked(true); + d->ui->m_emptyPayeesButton->setChecked(true); } else { - selectAllItems(m_ui->m_payeesView, false); - selectItems(m_ui->m_payeesView, payees, true); + d->selectAllItems(d->ui->m_payeesView, false); + d->selectItems(d->ui->m_payeesView, payees, true); } } else { - selectAllItems(m_ui->m_payeesView, true); + d->selectAllItems(d->ui->m_payeesView, true); } // // Tags Filter // QStringList tags; - if (m_initialState.tags(tags)) { + if (d->m_initialState.tags(tags)) { if (tags.empty()) { - m_ui->m_emptyTagsButton->setChecked(true); + d->ui->m_emptyTagsButton->setChecked(true); } else { - selectAllItems(m_ui->m_tagsView, false); - selectItems(m_ui->m_tagsView, tags, true); + d->selectAllItems(d->ui->m_tagsView, false); + d->selectItems(d->ui->m_tagsView, tags, true); } } else { - selectAllItems(m_ui->m_tagsView, true); + d->selectAllItems(d->ui->m_tagsView, true); } // // Accounts Filter // QStringList accounts; - if (m_initialState.accounts(accounts)) { - m_ui->m_accountsView->selectAllItems(false); - m_ui->m_accountsView->selectItems(accounts, true); + if (d->m_initialState.accounts(accounts)) { + d->ui->m_accountsView->selectAllItems(false); + d->ui->m_accountsView->selectItems(accounts, true); } else - m_ui->m_accountsView->selectAllItems(true); + d->ui->m_accountsView->selectAllItems(true); // // Categories Filter // - if (m_initialState.categories(accounts)) { - m_ui->m_categoriesView->selectAllItems(false); - m_ui->m_categoriesView->selectItems(accounts, true); + if (d->m_initialState.categories(accounts)) { + d->ui->m_categoriesView->selectAllItems(false); + d->ui->m_categoriesView->selectItems(accounts, true); } else - m_ui->m_categoriesView->selectAllItems(true); + d->ui->m_categoriesView->selectAllItems(true); // // Date Filter // // the following call implies a call to slotUpdateSelections, // that's why we call it last - m_initialState.updateDateFilter(); + d->m_initialState.updateDateFilter(); QDate dateFrom, dateTo; - if (m_initialState.dateFilter(dateFrom, dateTo)) { - if (m_initialState.isDateUserDefined()) { - m_dateRange->setDateRange(dateFrom, dateTo); + if (d->m_initialState.dateFilter(dateFrom, dateTo)) { + if (d->m_initialState.isDateUserDefined()) { + d->m_dateRange->setDateRange(dateFrom, dateTo); } else { - m_dateRange->setDateRange(m_initialState.dateRange()); + d->m_dateRange->setDateRange(d->m_initialState.dateRange()); } } else { - m_dateRange->setDateRange(eMyMoney::TransactionFilter::Date::All); + d->m_dateRange->setDateRange(eMyMoney::TransactionFilter::Date::All); } slotRightSize(); } void KReportConfigurationFilterDlg::slotShowHelp() { KHelpClient::invokeHelp("details.reports.config"); } //TODO Fix the reports and engine to include transfers even if categories are filtered - bug #1523508 void KReportConfigurationFilterDlg::slotUpdateCheckTransfers() { - QCheckBox* cb = m_tabRowColPivot->ui->m_checkTransfers; - if (!m_ui->m_categoriesView->allItemsSelected()) { + Q_D(KReportConfigurationFilterDlg); + auto cb = d->m_tabRowColPivot->ui->m_checkTransfers; + if (!d->ui->m_categoriesView->allItemsSelected()) { cb->setChecked(false); cb->setDisabled(true); } else { cb->setEnabled(true); } } diff --git a/kmymoney/dialogs/kreportconfigurationfilterdlg.h b/kmymoney/dialogs/kreportconfigurationfilterdlg.h index 0edc448f2..1cafdf461 100644 --- a/kmymoney/dialogs/kreportconfigurationfilterdlg.h +++ b/kmymoney/dialogs/kreportconfigurationfilterdlg.h @@ -1,90 +1,70 @@ /*************************************************************************** kreportconfigurationdlg.h - description ------------------- begin : Mon Jun 21 2004 copyright : (C) 2000-2004 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio Ace Jones + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KREPORTCONFIGURATIONFILTERDLG_H #define KREPORTCONFIGURATIONFILTERDLG_H // ---------------------------------------------------------------------------- // QT Includes -#include -#include - // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes #include "kfindtransactiondlg.h" -#include "mymoneyreport.h" -#include "mymoneybudget.h" -class ReportTabCapitalGain; -class ReportTabChart; -class ReportTabGeneral; -class ReportTabPerformance; -class ReportTabRange; -class ReportTabRowColPivot; -class ReportTabRowColQuery; +class MyMoneyReport; /** * @author Ace Jones */ +class KReportConfigurationFilterDlgPrivate; class KReportConfigurationFilterDlg : public KFindTransactionDlg { Q_OBJECT + Q_DISABLE_COPY(KReportConfigurationFilterDlg) + public: - explicit KReportConfigurationFilterDlg(MyMoneyReport report, QWidget *parent = 0); + explicit KReportConfigurationFilterDlg(MyMoneyReport report, QWidget *parent = nullptr); ~KReportConfigurationFilterDlg(); - const MyMoneyReport& getConfig() const { - return m_currentState; - } - -protected: - QPointer m_tabGeneral; - QPointer m_tabRowColPivot; - QPointer m_tabRowColQuery; - QPointer m_tabChart; - QPointer m_tabRange; - QPointer m_tabCapitalGain; - QPointer m_tabPerformance; - - MyMoneyReport m_initialState; - MyMoneyReport m_currentState; + MyMoneyReport getConfig() const; protected slots: void slotRowTypeChanged(int); void slotColumnTypeChanged(int); void slotReset(); void slotSearch(); void slotShowHelp(); void slotUpdateCheckTransfers(); void slotUpdateColumnsCombo(); + void slotUpdateColumnsCombo(int idx); void slotLogAxisChanged(int state); private: - QVector m_budgets; + Q_DECLARE_PRIVATE(KReportConfigurationFilterDlg) }; #endif diff --git a/kmymoney/dialogs/kselectdatabasedlg.cpp b/kmymoney/dialogs/kselectdatabasedlg.cpp index b1dac227d..8a10b139b 100644 --- a/kmymoney/dialogs/kselectdatabasedlg.cpp +++ b/kmymoney/dialogs/kselectdatabasedlg.cpp @@ -1,231 +1,232 @@ /*************************************************************************** kselectdatabasedlg.cpp ------------------- copyright : (C) 2005 by Tony Bloomfield (C) 2017 by Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kselectdatabasedlg.h" #include // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes #include #include // ---------------------------------------------------------------------------- // Project Includes #include "ui_kselectdatabasedlg.h" #include "kguiutils.h" #include "storage/mymoneystoragesql.h" #include "misc/platformtools.h" KSelectDatabaseDlg::KSelectDatabaseDlg(int openMode, QUrl openURL, QWidget *) : m_widget(new Ui::KSelectDatabaseDlg()) , m_mode(openMode) , m_url(openURL) , m_requiredFields(new kMandatoryFieldGroup(this)) , m_sqliteSelected(false) { m_widget->setupUi(this); connect(m_widget->buttonBox, &QDialogButtonBox::accepted, this, &KSelectDatabaseDlg::accept); connect(m_widget->buttonBox, &QDialogButtonBox::rejected, this, &KSelectDatabaseDlg::reject); connect(m_widget->buttonBox->button(QDialogButtonBox::Help), &QPushButton::clicked, this, &KSelectDatabaseDlg::slotHelp); m_requiredFields->setOkButton(m_widget->buttonBox->button(QDialogButtonBox::Ok)); m_widget->checkPreLoad->setEnabled(openMode == QIODevice::ReadWrite); } KSelectDatabaseDlg::~KSelectDatabaseDlg() { } bool KSelectDatabaseDlg::checkDrivers() { QString driverName; if (m_url != QUrl()) { driverName = QUrlQuery(m_url).queryItemValue("driver"); } // list drivers supported by KMM QMap map = MyMoneyDbDriver::driverMap(); // list drivers installed on system QStringList list = QSqlDatabase::drivers(); // clear out the current list of drivers while(m_widget->databaseTypeCombo->count()) { m_widget->databaseTypeCombo->removeItem(0); } // join the two QStringList::Iterator it = list.begin(); bool driverSupported = false; while (it != list.end()) { QString dname = *it; if (map.keys().contains(dname)) { // only keep if driver is supported m_widget->databaseTypeCombo->addItem(map[dname], dname); if (driverName == dname) { driverSupported = true; } } it++; } if (!driverName.isEmpty() && !driverSupported) { KMessageBox::error(0, i18n("Qt SQL driver %1 is no longer installed on your system", driverName), ""); return false; } if (m_widget->databaseTypeCombo->count() == 0) { // why does KMessageBox not have a standard dialog with Help button? if ((KMessageBox::questionYesNo(this, i18n("In order to use a database, you need to install some additional software. Click Help for more information"), i18n("No Qt SQL Drivers"), KStandardGuiItem::help(), KStandardGuiItem::cancel())) == KMessageBox::Yes) { // Yes stands in for help here KHelpClient::invokeHelp("details.database.usage"); } return false; } return true; } int KSelectDatabaseDlg::exec() { m_requiredFields->removeAll(); if (m_url == QUrl()) { m_widget->textDbName->setText(QLatin1String("KMyMoney")); m_widget->textHostName->setText(QLatin1String("localhost")); m_widget->textUserName->setText(QString()); m_widget->textUserName->setText(platformTools::osUsername()); m_widget->textPassword->setText(QString()); - connect(m_widget->databaseTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotDriverSelected(int))); + connect(m_widget->databaseTypeCombo, static_cast(&QComboBox::currentIndexChanged), this, &KSelectDatabaseDlg::slotDriverSelected); m_widget->checkPreLoad->setChecked(false); // ensure a driver gets selected; pre-select the first one if (m_widget->databaseTypeCombo->count() != 0) { m_widget->databaseTypeCombo->setCurrentIndex(0); slotDriverSelected(0); } } else { // fill in the fixed data from the URL QString driverName = QUrlQuery(m_url).queryItemValue("driver"); int idx = m_widget->databaseTypeCombo->findData(driverName); m_widget->databaseTypeCombo->setCurrentIndex(idx); QString dbName = m_url.path().right(m_url.path().length() - 1); // remove separator slash m_widget->textDbName->setText(dbName); m_widget->textHostName->setText(m_url.host()); m_widget->textUserName->setText(m_url.userName()); // disable all but the password field, coz that's why we're here m_widget->textDbName->setEnabled(false); m_widget->urlSqlite->setEnabled(false); m_widget->databaseTypeCombo->setEnabled(false); m_widget->textHostName->setEnabled(false); m_widget->textUserName->setEnabled(false); m_widget->textPassword->setEnabled(true); m_widget->textPassword->setFocus(); // set password required m_requiredFields->add(m_widget->textPassword); m_widget->checkPreLoad->setChecked(false); m_sqliteSelected = !m_widget->urlSqlite->text().isEmpty(); } return QDialog::exec(); } const QUrl KSelectDatabaseDlg::selectedURL() { QUrl url; url.setScheme("sql"); url.setUserName(m_widget->textUserName->text()); url.setPassword(m_widget->textPassword->text()); url.setHost(m_widget->textHostName->text()); if (m_sqliteSelected) url.setPath('/' + m_widget->urlSqlite->url().path()); else url.setPath('/' + m_widget->textDbName->text()); QString qs = QString("driver=%1") .arg(m_widget->databaseTypeCombo->currentData().toString()); if (m_widget->checkPreLoad->isChecked()) qs.append("&options=loadAll"); if (!m_widget->textPassword->text().isEmpty()) qs.append("&secure=yes"); url.setQuery(qs); return (url); } void KSelectDatabaseDlg::slotDriverSelected(int idx) { QExplicitlySharedDataPointer dbDriver = MyMoneyDbDriver::create(m_widget->databaseTypeCombo->itemData(idx).toString()); if (!dbDriver->isTested()) { int rc = KMessageBox::warningContinueCancel(0, i18n("Database type %1 has not been fully tested in a KMyMoney environment.\n" "Please make sure you have adequate backups of your data.\n" "Please report any problems to the developer mailing list at " "kmymoney-devel@kde.org", m_widget->databaseTypeCombo->currentText()), ""); if (rc == KMessageBox::Cancel) { return; } } m_requiredFields->removeAll(); if (dbDriver->requiresExternalFile()) { // currently, only sqlite requres an external file m_sqliteSelected = true; if (m_mode == QIODevice::WriteOnly) { m_widget->urlSqlite->setMode(KFile::Mode::File); } else { m_widget->urlSqlite->setMode(KFile::Mode::File | KFile::Mode::ExistingOnly); } m_widget->textDbName->setEnabled(false); m_widget->urlSqlite->setEnabled(true); // sqlite databases do not react to host/user/password; // file system permissions must be used m_widget->textHostName->setEnabled(false); m_widget->textUserName->setEnabled(false); // setup required fields last because the required widgets must be enabled m_requiredFields->add(m_widget->urlSqlite); } else { // not sqlite3 m_sqliteSelected = false; m_widget->textDbName->setEnabled(true); m_widget->urlSqlite->setEnabled(false); m_widget->textUserName->setEnabled(true); m_widget->textHostName->setEnabled(true); // setup required fields last because the required widgets must be enabled m_requiredFields->add(m_widget->textDbName); m_requiredFields->add(m_widget->textHostName); m_requiredFields->add(m_widget->textUserName); } m_widget->textPassword->setEnabled(dbDriver->isPasswordSupported()); } void KSelectDatabaseDlg::slotHelp() { KHelpClient::invokeHelp("details.database.selectdatabase"); } diff --git a/kmymoney/dialogs/kselectdatabasedlg.h b/kmymoney/dialogs/kselectdatabasedlg.h index 4c4ddf5b8..70fcdbc24 100644 --- a/kmymoney/dialogs/kselectdatabasedlg.h +++ b/kmymoney/dialogs/kselectdatabasedlg.h @@ -1,73 +1,74 @@ /*************************************************************************** kselectdatabase.h ------------------- copyright : (C) 2005 by Tony Bloomfield + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSELECTDATABASEDLG_H #define KSELECTDATABASEDLG_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes namespace Ui { class KSelectDatabaseDlg; } class kMandatoryFieldGroup; class KSelectDatabaseDlg : public QDialog { Q_OBJECT public: - explicit KSelectDatabaseDlg(int openMode, QUrl openURL = QUrl(), QWidget *parent = 0); + explicit KSelectDatabaseDlg(int openMode, QUrl openURL = QUrl(), QWidget *parent = nullptr); ~KSelectDatabaseDlg(); /** * Check whether we have required database drivers * @return - false, no drivers available, true, can proceed */ bool checkDrivers(); /** * Return URL of database * @return - pseudo-URL of database selected by user */ const QUrl selectedURL(); /** * Execute the database selection dialog * @return - as QDialog::exec() */ - int exec(); + int exec() override; public slots: void slotDriverSelected(int idx); void slotHelp(); private: Ui::KSelectDatabaseDlg* m_widget; int m_mode; QUrl m_url; kMandatoryFieldGroup* m_requiredFields; bool m_sqliteSelected; }; #endif diff --git a/kmymoney/dialogs/kselecttransactionsdlg.cpp b/kmymoney/dialogs/kselecttransactionsdlg.cpp index 3796df619..ac94e5df0 100644 --- a/kmymoney/dialogs/kselecttransactionsdlg.cpp +++ b/kmymoney/dialogs/kselecttransactionsdlg.cpp @@ -1,179 +1,202 @@ /*************************************************************************** kselecttransactionsdlg.cpp ------------------- begin : Wed May 16 2007 copyright : (C) 2007 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kselecttransactionsdlg.h" +#include "kselecttransactionsdlg_p.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kselecttransactionsdlg.h" + +#include "mymoneyaccount.h" +#include "selectedtransaction.h" #include "mymoneytransaction.h" #include "kmymoneyglobalsettings.h" -#include -#include KSelectTransactionsDlg::KSelectTransactionsDlg(const MyMoneyAccount& _account, QWidget* parent) : - KSelectTransactionsDlgDecl(parent), - m_account(_account) + QDialog(parent), + d_ptr(new KSelectTransactionsDlgPrivate) { + Q_D(KSelectTransactionsDlg); + d->m_account = _account; + d->ui->setupUi(this); // setup descriptive texts setWindowTitle(i18n("Select Transaction")); - m_description->setText(i18n("Select a transaction and press the OK button or use Cancel to select none.")); + d->ui->m_description->setText(i18n("Select a transaction and press the OK button or use Cancel to select none.")); // clear current register contents - m_register->clear(); + d->ui->m_register->clear(); // no selection possible - m_register->setSelectionMode(QTableWidget::SingleSelection); + d->ui->m_register->setSelectionMode(QTableWidget::SingleSelection); // setup header font - QFont font = KMyMoneyGlobalSettings::listHeaderFont(); + auto font = KMyMoneyGlobalSettings::listHeaderFont(); QFontMetrics fm(font); - int height = fm.lineSpacing() + 6; - m_register->horizontalHeader()->setMinimumHeight(height); - m_register->horizontalHeader()->setMaximumHeight(height); - m_register->horizontalHeader()->setFont(font); + auto height = fm.lineSpacing() + 6; + d->ui->m_register->horizontalHeader()->setMinimumHeight(height); + d->ui->m_register->horizontalHeader()->setMaximumHeight(height); + d->ui->m_register->horizontalHeader()->setFont(font); // setup cell font font = KMyMoneyGlobalSettings::listCellFont(); - m_register->setFont(font); + d->ui->m_register->setFont(font); // ... setup the register columns ... - m_register->setupRegister(m_account); + d->ui->m_register->setupRegister(d->m_account); // setup buttons - KGuiItem::assign(m_helpButton, KStandardGuiItem::help()); - KGuiItem::assign(buttonOk, KStandardGuiItem::ok()); - KGuiItem::assign(buttonCancel, KStandardGuiItem::cancel()); // default is to need at least one transaction selected - buttonOk->setDisabled(true); + d->ui->buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true); // catch some events from the register - m_register->installEventFilter(this); + d->ui->m_register->installEventFilter(this); - connect(m_register, SIGNAL(transactionsSelected(KMyMoneyRegister::SelectedTransactions)), this, SLOT(slotEnableOk(KMyMoneyRegister::SelectedTransactions))); - connect(m_register, SIGNAL(editTransaction()), this, SLOT(accept())); + connect(d->ui->m_register, &KMyMoneyRegister::Register::transactionsSelected, this, &KSelectTransactionsDlg::slotEnableOk); + connect(d->ui->m_register, &KMyMoneyRegister::Register::editTransaction, this, &QDialog::accept); + + connect(d->ui->buttonBox, &QDialogButtonBox::helpRequested, this, &KSelectTransactionsDlg::slotHelp); +} - connect(m_helpButton, SIGNAL(clicked()), this, SLOT(slotHelp())); +KSelectTransactionsDlg::~KSelectTransactionsDlg() +{ + Q_D(KSelectTransactionsDlg); + delete d; } void KSelectTransactionsDlg::slotEnableOk(const KMyMoneyRegister::SelectedTransactions& list) { - buttonOk->setEnabled(list.count() != 0); + Q_D(KSelectTransactionsDlg); + d->ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(list.count() != 0); } void KSelectTransactionsDlg::addTransaction(const MyMoneyTransaction& t) { + Q_D(KSelectTransactionsDlg); QList::const_iterator it_s; for (it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) { - if ((*it_s).accountId() == m_account.id()) { - KMyMoneyRegister::Transaction* tr = KMyMoneyRegister::Register::transactionFactory(m_register, t, (*it_s), 0); + if ((*it_s).accountId() == d->m_account.id()) { + KMyMoneyRegister::Transaction* tr = KMyMoneyRegister::Register::transactionFactory(d->ui->m_register, t, (*it_s), 0); // force full detail display tr->setNumRowsRegister(tr->numRowsRegister(true)); break; } } } int KSelectTransactionsDlg::exec() { - m_register->updateRegister(true); - m_register->update(); + Q_D(KSelectTransactionsDlg); + d->ui->m_register->updateRegister(true); + d->ui->m_register->update(); - m_register->setFocus(); + d->ui->m_register->setFocus(); - return KSelectTransactionsDlgDecl::exec(); + return QDialog::exec(); } void KSelectTransactionsDlg::slotHelp() { // KHelpClient::invokeHelp("details.ledgers.match"); } void KSelectTransactionsDlg::showEvent(QShowEvent* event) { - KSelectTransactionsDlgDecl::showEvent(event); - m_register->resize(KMyMoneyRegister::DetailColumn, true); + Q_D(KSelectTransactionsDlg); + QDialog::showEvent(event); + d->ui->m_register->resize(KMyMoneyRegister::DetailColumn, true); } void KSelectTransactionsDlg::resizeEvent(QResizeEvent* ev) { + Q_D(KSelectTransactionsDlg); // don't forget the resizer - KSelectTransactionsDlgDecl::resizeEvent(ev); + QDialog::resizeEvent(ev); // resize the register - m_register->resize(KMyMoneyRegister::DetailColumn, true); + d->ui->m_register->resize(KMyMoneyRegister::DetailColumn, true); } MyMoneyTransaction KSelectTransactionsDlg::transaction() const { + Q_D(const KSelectTransactionsDlg); MyMoneyTransaction t; QList list; - list = m_register->selectedItems(); + list = d->ui->m_register->selectedItems(); if (list.count()) { KMyMoneyRegister::Transaction* _t = dynamic_cast(list[0]); if (_t) t = _t->transaction(); } return t; } +KMyMoneyRegister::Register* KSelectTransactionsDlg::getRegister() +{ + Q_D(KSelectTransactionsDlg); + return d->ui->m_register; +} + bool KSelectTransactionsDlg::eventFilter(QObject* o, QEvent* e) { - bool rc = false; + Q_D(KSelectTransactionsDlg); + auto rc = false; QKeyEvent* k; - if (o == m_register) { + if (o == d->ui->m_register) { switch (e->type()) { case QEvent::KeyPress: k = dynamic_cast(e); if ((k->modifiers() & Qt::KeyboardModifierMask) == 0 || (k->modifiers() & Qt::KeypadModifier) != 0) { switch (k->key()) { case Qt::Key_Return: case Qt::Key_Enter: - if (buttonOk->isEnabled()) { + if (d->ui->buttonBox->button(QDialogButtonBox::Ok)->isEnabled()) { accept(); rc = true; } // tricky fall through here default: break; } } // tricky fall through here default: break; } } return rc; } diff --git a/kmymoney/dialogs/kselecttransactionsdlg.h b/kmymoney/dialogs/kselecttransactionsdlg.h index 320cb7b96..8a68a24ec 100644 --- a/kmymoney/dialogs/kselecttransactionsdlg.h +++ b/kmymoney/dialogs/kselecttransactionsdlg.h @@ -1,77 +1,74 @@ /*************************************************************************** kselecttransactionsdlg.h ------------------- begin : Wed May 16 2007 copyright : (C) 2007 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSELECTTRANSACTIONSDLG_H #define KSELECTTRANSACTIONSDLG_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "mymoneyaccount.h" -#include "selectedtransaction.h" - -#include "ui_kselecttransactionsdlgdecl.h" - class MyMoneyTransaction; +class MyMoneyAccount; -class KSelectTransactionsDlgDecl : public QDialog, public Ui::KSelectTransactionsDlgDecl -{ -public: - KSelectTransactionsDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; -class KSelectTransactionsDlg: public KSelectTransactionsDlgDecl +namespace KMyMoneyRegister { class SelectedTransactions; class Register;} + +class KSelectTransactionsDlgPrivate; +class KSelectTransactionsDlg: public QDialog { Q_OBJECT + Q_DISABLE_COPY(KSelectTransactionsDlg) + public: - explicit KSelectTransactionsDlg(const MyMoneyAccount& account, QWidget* parent = 0); + explicit KSelectTransactionsDlg(const MyMoneyAccount& account, QWidget* parent = nullptr); + ~KSelectTransactionsDlg(); /** * Adds the transaction @a t to the dialog */ void addTransaction(const MyMoneyTransaction& t); - int exec(); + int exec() override; MyMoneyTransaction transaction() const; + KMyMoneyRegister::Register *getRegister(); - bool eventFilter(QObject* o, QEvent* e); + bool eventFilter(QObject* o, QEvent* e) override; public slots: virtual void slotHelp(); protected slots: void slotEnableOk(const KMyMoneyRegister::SelectedTransactions& list); protected: - void resizeEvent(QResizeEvent* ev); - void showEvent(QShowEvent* event); + void resizeEvent(QResizeEvent* ev) override; + void showEvent(QShowEvent* event) override; + KSelectTransactionsDlgPrivate * const d_ptr; private: - /** - * The account in which the transactions are displayed - */ - MyMoneyAccount m_account; + Q_DECLARE_PRIVATE(KSelectTransactionsDlg) }; #endif // KMERGETRANSACTIONSDLG_H diff --git a/kmymoney/dialogs/kselecttransactionsdlg.ui b/kmymoney/dialogs/kselecttransactionsdlg.ui new file mode 100644 index 000000000..7c1617e8d --- /dev/null +++ b/kmymoney/dialogs/kselecttransactionsdlg.ui @@ -0,0 +1,101 @@ + + + KSelectTransactionsDlg + + + + 0 + 0 + 794 + 456 + + + + xxx + + + true + + + + + + Qt::NoFocus + + + xxx + + + true + + + + + + + + 0 + 3 + + + + 0 + + + 12 + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok + + + + + + + + + KMyMoneyRegister::Register + QWidget +
register.h
+
+
+ + + + buttonBox + accepted() + KSelectTransactionsDlg + accept() + + + 396 + 432 + + + 396 + 227 + + + + + buttonBox + rejected() + KSelectTransactionsDlg + reject() + + + 396 + 432 + + + 396 + 227 + + + + +
diff --git a/kmymoney/dialogs/settings/ksettingscolors.h b/kmymoney/dialogs/kselecttransactionsdlg_p.h similarity index 64% copy from kmymoney/dialogs/settings/ksettingscolors.h copy to kmymoney/dialogs/kselecttransactionsdlg_p.h index 2c18632b8..6d956f2c5 100644 --- a/kmymoney/dialogs/settings/ksettingscolors.h +++ b/kmymoney/dialogs/kselecttransactionsdlg_p.h @@ -1,47 +1,57 @@ /*************************************************************************** - ksettingscolors.h + kselecttransactionsdlg_p.h ------------------- - copyright : (C) 2005 by Thomas Baumgart + begin : Wed May 16 2007 + copyright : (C) 2007 by Thomas Baumgart email : ipwizard@users.sourceforge.net - (C) 2017 by Łukasz Wojniłowicz + (C) 2017 by Ł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. * * * ***************************************************************************/ -#ifndef KSETTINGSCOLORS_H -#define KSETTINGSCOLORS_H +#ifndef KSELECTTRANSACTIONSDLG_P_H +#define KSELECTTRANSACTIONSDLG_P_H // ---------------------------------------------------------------------------- // QT Includes // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ksettingscolors.h" +#include "ui_kselecttransactionsdlg.h" -class KSettingsColors : public QWidget, public Ui::KSettingsColors +#include "mymoneyaccount.h" + +class KSelectTransactionsDlgPrivate { - Q_OBJECT + Q_DISABLE_COPY(KSelectTransactionsDlgPrivate) public: - explicit KSettingsColors(QWidget* parent = nullptr); - ~KSettingsColors(); - -private slots: - /** - * This presets custom colors with system's color scheme - */ - void slotCustomColorsToggled(bool); + KSelectTransactionsDlgPrivate() : + ui(new Ui::KSelectTransactionsDlg) + { + } + + ~KSelectTransactionsDlgPrivate() + { + delete ui; + } + + Ui::KSelectTransactionsDlg *ui; + /** + * The account in which the transactions are displayed + */ + MyMoneyAccount m_account; }; -#endif +#endif // KMERGETRANSACTIONSDLG_H diff --git a/kmymoney/dialogs/kselecttransactionsdlgdecl.ui b/kmymoney/dialogs/kselecttransactionsdlgdecl.ui deleted file mode 100644 index 1bbf465d9..000000000 --- a/kmymoney/dialogs/kselecttransactionsdlgdecl.ui +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - KSelectTransactionsDlgDecl - - - - 0 - 0 - 794 - 456 - - - - xxx - - - true - - - - - - Qt::NoFocus - - - xxx - - - true - - - - - - - - 7 - 7 - 0 - 3 - - - - 0 - - - 12 - - - - Security - - - - - Details - - - - - C - - - - - Payment - - - - - Deposit - - - - - Quantity - - - - - Price - - - - - Value - - - - - Balance - - - - - - - - - - Help - - - - - - - - 430 - 20 - - - - QSizePolicy::Expanding - - - Qt::Horizontal - - - - - - - OK - - - true - - - true - - - - - - - Cancel - - - - - - - - - - - buttonOk - clicked() - KSelectTransactionsDlgDecl - accept() - - - buttonCancel - clicked() - KSelectTransactionsDlgDecl - reject() - - - diff --git a/kmymoney/dialogs/ksplitcorrectiondlg.ui b/kmymoney/dialogs/ksplitcorrectiondlg.ui index 1b1b21b6d..8ae71a3d4 100644 --- a/kmymoney/dialogs/ksplitcorrectiondlg.ui +++ b/kmymoney/dialogs/ksplitcorrectiondlg.ui @@ -1,163 +1,219 @@ - - - - - KSplitCorrectionDlgDecl - - - - 0 - 0 - 462 - 292 - - - - - 80 - 0 - - - - Correct splits - - - - - 0 - 0 - - + + KSplitCorrectionDlg + + + Qt::ApplicationModal + + + + 0 + 0 + 462 + 292 + + + + + 80 + 0 + + + + Correct splits + + + - - 11 - - - 6 - - - + + 6 + + + 11 + + + 11 + + + 11 + + + 11 + + + + + + + Qt::NoFocus + + + xxx + + + true + + + + + + + true + + + How do you want to proceed? + + + false + + + + + + + QFrame::NoFrame + + + + 6 + + + 11 + + + 11 + + + 11 + + + 11 + - - - Qt::NoFocus - - - xxx - - - true - - + + + Co&ntinue to edit splits + + + true + + + buttonGroup + + - - - true - - - How do you want to proceed? - - - false - - + + + Chan&ge total amount of transaction to %1. + + + buttonGroup + + - - - QFrame::NoFrame - - - - 11 - - - 6 - - - - - Continue to edit splits - - - true - - - buttonGroup - - - - - - - Change total amount of transaction to %1. - - - buttonGroup - - - - - - - false - - - Distribute difference of %1 among all splits. - - - buttonGroup - - - - - - - Leave %1 unassigned. - - - buttonGroup - - - - - + + + false + + + Distrib&ute difference of %1 among all splits. + + + buttonGroup + + - - - - - - - 20 - 41 - - - - QSizePolicy::Expanding - - - Qt::Vertical - - - - - - - QFrame::HLine - - - QFrame::Sunken - + + + + Leave %&1 unassigned. + + + buttonGroup + + + + - + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 41 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + - - - - - - + + + + + + + + buttonBox + accepted() + KSplitCorrectionDlg + accept() + + + 230 + 248 + + + 230 + 145 + + + + + buttonBox + rejected() + KSplitCorrectionDlg + reject() + + + 230 + 248 + + + 230 + 145 + + + + + + + diff --git a/kmymoney/dialogs/ksplittransactiondlg.cpp b/kmymoney/dialogs/ksplittransactiondlg.cpp index 691f26bb9..6785e3e34 100644 --- a/kmymoney/dialogs/ksplittransactiondlg.cpp +++ b/kmymoney/dialogs/ksplittransactiondlg.cpp @@ -1,477 +1,568 @@ /*************************************************************************** ksplittransactiondlg.cpp - description ------------------- begin : Thu Jan 10 2002 copyright : (C) 2000-2002 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "ksplittransactiondlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include -#include #include #include #include -#include -#include +#include // ---------------------------------------------------------------------------- // KDE Includes #include #include -#include #include #include #include // ---------------------------------------------------------------------------- // Project Includes -#include "kmymoneyedit.h" -#include "kmymoneylineedit.h" +#include "ui_ksplittransactiondlg.h" +#include "ui_ksplitcorrectiondlg.h" + #include "mymoneyfile.h" -#include "mymoneysecurity.h" #include "kmymoneysplittable.h" +#include "mymoneymoney.h" +#include "mymoneyaccount.h" +#include "mymoneysecurity.h" +#include "mymoneysplit.h" +#include "mymoneytransaction.h" #include "icons/icons.h" using namespace Icons; +KSplitCorrectionDlg::KSplitCorrectionDlg(QWidget *parent) : + QDialog(parent), + ui(new Ui::KSplitCorrectionDlg) +{ + ui->setupUi(this); +} + +KSplitCorrectionDlg::~KSplitCorrectionDlg() +{ + delete ui; +} + +class KSplitTransactionDlgPrivate +{ + Q_DISABLE_COPY(KSplitTransactionDlgPrivate) + Q_DECLARE_PUBLIC(KSplitTransactionDlg) + +public: + KSplitTransactionDlgPrivate(KSplitTransactionDlg *qq) : + q_ptr(qq), + ui(new Ui::KSplitTransactionDlg) + { + } + + ~KSplitTransactionDlgPrivate() + { + delete ui; + } + + void init(const MyMoneyTransaction& t, const QMap& priceInfo) + { + Q_Q(KSplitTransactionDlg); + ui->setupUi(q); + q->setModal(true); + + auto okButton = ui->buttonBox->button(QDialogButtonBox::Ok); + okButton->setDefault(true); + okButton->setShortcut(Qt::CTRL | Qt::Key_Return); + auto user1Button = new QPushButton; + ui->buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole); + auto user2Button = new QPushButton; + ui->buttonBox->addButton(user2Button, QDialogButtonBox::ActionRole); + auto user3Button = new QPushButton; + ui->buttonBox->addButton(user3Button, QDialogButtonBox::ActionRole); + + //set custom buttons + //clearAll button + user1Button->setText(i18n("Clear &All")); + user1Button->setToolTip(i18n("Clear all splits")); + user1Button->setWhatsThis(i18n("Use this to clear all splits of this transaction")); + user1Button->setIcon(QIcon::fromTheme(g_Icons[Icon::EditClear])); + + //clearZero button + user2Button->setText(i18n("Clear &Zero")); + user2Button->setToolTip(i18n("Removes all splits that have a value of zero")); + user2Button->setIcon(QIcon::fromTheme(g_Icons[Icon::EditClear])); + + //merge button + user3Button->setText(i18n("&Merge")); + user3Button->setToolTip(i18n("Merges splits with the same category to one split")); + user3Button->setWhatsThis(i18n("In case you have multiple split entries to the same category and you like to keep them as a single split")); + + // make finish the default + ui->buttonBox->button(QDialogButtonBox::Cancel)->setDefault(true); + + // setup the focus + ui->buttonBox->button(QDialogButtonBox::Cancel)->setFocusPolicy(Qt::NoFocus); + okButton->setFocusPolicy(Qt::NoFocus); + user1Button->setFocusPolicy(Qt::NoFocus); + + // q->connect signals with slots + q->connect(ui->transactionsTable, &KMyMoneySplitTable::transactionChanged, + q, &KSplitTransactionDlg::slotSetTransaction); + q->connect(ui->transactionsTable, &KMyMoneySplitTable::createCategory, q, &KSplitTransactionDlg::slotCreateCategory); + q->connect(ui->transactionsTable, &KMyMoneySplitTable::objectCreation, q, &KSplitTransactionDlg::objectCreation); + + q->connect(ui->transactionsTable, &KMyMoneySplitTable::returnPressed, q, &KSplitTransactionDlg::accept); + q->connect(ui->transactionsTable, &KMyMoneySplitTable::escapePressed, q, &KSplitTransactionDlg::reject); + q->connect(ui->transactionsTable, &KMyMoneySplitTable::editStarted, q, &KSplitTransactionDlg::slotEditStarted); + q->connect(ui->transactionsTable, &KMyMoneySplitTable::editFinished, q, &KSplitTransactionDlg::slotUpdateButtons); + + q->connect(ui->buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, q, &KSplitTransactionDlg::reject); + q->connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, q, &KSplitTransactionDlg::accept); + q->connect(user1Button, &QAbstractButton::clicked, q, &KSplitTransactionDlg::slotClearAllSplits); + q->connect(user3Button, &QAbstractButton::clicked, q, &KSplitTransactionDlg::slotMergeSplits); + q->connect(user2Button, &QAbstractButton::clicked, q, &KSplitTransactionDlg::slotClearUnusedSplits); + + // setup the precision + try { + auto currency = MyMoneyFile::instance()->currency(t.commodity()); + m_precision = MyMoneyMoney::denomToPrec(m_account.fraction(currency)); + } catch (const MyMoneyException &) { + } + + q->slotSetTransaction(t); + + // pass on those vars + ui->transactionsTable->setup(priceInfo, m_precision); + + QSize size(q->width(), q->height()); + KConfigGroup grp = KSharedConfig::openConfig()->group("SplitTransactionEditor"); + size = grp.readEntry("Geometry", size); + size.setHeight(size.height() - 1); + q->resize(size.expandedTo(q->minimumSizeHint())); + + // Trick: it seems, that the initial sizing of the dialog does + // not work correctly. At least, the columns do not get displayed + // correct. Reason: the return value of ui->transactionsTable->visibleWidth() + // is incorrect. If the widget is visible, resizing works correctly. + // So, we let the dialog show up and resize it then. It's not really + // clean, but the only way I got the damned thing working. + QTimer::singleShot(10, q, SLOT(initSize())); + + } + + /** + * This method updates the display of the sums below the register + */ + void updateSums() + { + Q_Q(KSplitTransactionDlg); + MyMoneyMoney splits(q->splitsValue()); + + if (m_amountValid == false) { + m_split.setValue(-splits); + m_transaction.modifySplit(m_split); + } + + ui->splitSum->setText("" + splits.formatMoney(QString(), m_precision) + ' '); + ui->splitUnassigned->setText("" + q->diffAmount().formatMoney(QString(), m_precision) + ' '); + ui->transactionAmount->setText("" + (-m_split.value()).formatMoney(QString(), m_precision) + ' '); + } + + KSplitTransactionDlg *q_ptr; + Ui::KSplitTransactionDlg *ui; + QDialogButtonBox *m_buttonBox; + /** + * This member keeps a copy of the current selected transaction + */ + MyMoneyTransaction m_transaction; + + /** + * This member keeps a copy of the currently selected account + */ + MyMoneyAccount m_account; + + /** + * This member keeps a copy of the currently selected split + */ + MyMoneySplit m_split; + + /** + * This member keeps the precision for the values + */ + int m_precision; + + /** + * flag that shows that the amount specified in the constructor + * should be used as fix value (true) or if it can be changed (false) + */ + bool m_amountValid; + + /** + * This member keeps track if the current transaction is of type + * deposit (true) or withdrawal (false). + */ + bool m_isDeposit; + + /** + * This member keeps the amount that will be assigned to all the + * splits that are marked 'will be calculated'. + */ + MyMoneyMoney m_calculatedValue; +}; + KSplitTransactionDlg::KSplitTransactionDlg(const MyMoneyTransaction& t, const MyMoneySplit& s, const MyMoneyAccount& acc, const bool amountValid, const bool deposit, const MyMoneyMoney& calculatedValue, const QMap& priceInfo, QWidget* parent) : - KSplitTransactionDlgDecl(parent), - m_account(acc), - m_split(s), - m_precision(2), - m_amountValid(amountValid), - m_isDeposit(deposit), - m_calculatedValue(calculatedValue) + QDialog(parent), + d_ptr(new KSplitTransactionDlgPrivate(this)) { - setModal(true); - - QHBoxLayout *mainLayout = new QHBoxLayout; - setLayout(mainLayout); - mainLayout->addWidget(horizontalLayoutWidget); - - m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); - QPushButton *okButton = m_buttonBox->button(QDialogButtonBox::Ok); - okButton->setDefault(true); - okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - QPushButton *user1Button = new QPushButton; - m_buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole); - QPushButton *user2Button = new QPushButton; - m_buttonBox->addButton(user2Button, QDialogButtonBox::ActionRole); - QPushButton *user3Button = new QPushButton; - m_buttonBox->addButton(user3Button, QDialogButtonBox::ActionRole); - connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - m_buttonBox->setOrientation(Qt::Vertical); - mainLayout->addWidget(m_buttonBox); - - //set custom buttons - //clearAll button - user1Button->setText(i18n("Clear &All")); - user1Button->setToolTip(i18n("Clear all splits")); - user1Button->setWhatsThis(i18n("Use this to clear all splits of this transaction")); - user1Button->setIcon(QIcon::fromTheme(g_Icons[Icon::EditClear])); - - //clearZero button - user2Button->setText(i18n("Clear &Zero")); - user2Button->setToolTip(i18n("Removes all splits that have a value of zero")); - user2Button->setIcon(QIcon::fromTheme(g_Icons[Icon::EditClear])); - - //merge button - user3Button->setText(i18n("&Merge")); - user3Button->setToolTip(i18n("Merges splits with the same category to one split")); - user3Button->setWhatsThis(i18n("In case you have multiple split entries to the same category and you like to keep them as a single split")); - - // make finish the default - m_buttonBox->button(QDialogButtonBox::Cancel)->setDefault(true); - - // setup the focus - m_buttonBox->button(QDialogButtonBox::Cancel)->setFocusPolicy(Qt::NoFocus); - okButton->setFocusPolicy(Qt::NoFocus); - user1Button->setFocusPolicy(Qt::NoFocus); - - // connect signals with slots - connect(transactionsTable, SIGNAL(transactionChanged(MyMoneyTransaction)), - this, SLOT(slotSetTransaction(MyMoneyTransaction))); - connect(transactionsTable, SIGNAL(createCategory(QString,QString&)), this, SLOT(slotCreateCategory(QString,QString&))); - connect(transactionsTable, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); - - connect(transactionsTable, SIGNAL(returnPressed()), this, SLOT(accept())); - connect(transactionsTable, SIGNAL(escapePressed()), this, SLOT(reject())); - connect(transactionsTable, SIGNAL(editStarted()), this, SLOT(slotEditStarted())); - connect(transactionsTable, SIGNAL(editFinished()), this, SLOT(slotUpdateButtons())); - - connect(m_buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject())); - connect(m_buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept())); - connect(user1Button, SIGNAL(clicked()), this, SLOT(slotClearAllSplits())); - connect(user3Button, SIGNAL(clicked()), this, SLOT(slotMergeSplits())); - connect(user2Button, SIGNAL(clicked()), this, SLOT(slotClearUnusedSplits())); - - // setup the precision - try { - MyMoneySecurity currency = MyMoneyFile::instance()->currency(t.commodity()); - m_precision = MyMoneyMoney::denomToPrec(m_account.fraction(currency)); - } catch (const MyMoneyException &) { - } - - slotSetTransaction(t); - - // pass on those vars - transactionsTable->setup(priceInfo, m_precision); - - QSize size(width(), height()); - KConfigGroup grp = KSharedConfig::openConfig()->group("SplitTransactionEditor"); - size = grp.readEntry("Geometry", size); - size.setHeight(size.height() - 1); - QDialog::resize(size.expandedTo(minimumSizeHint())); - - // Trick: it seems, that the initial sizing of the dialog does - // not work correctly. At least, the columns do not get displayed - // correct. Reason: the return value of transactionsTable->visibleWidth() - // is incorrect. If the widget is visible, resizing works correctly. - // So, we let the dialog show up and resize it then. It's not really - // clean, but the only way I got the damned thing working. - QTimer::singleShot(10, this, SLOT(initSize())); + Q_D(KSplitTransactionDlg); + d->ui->buttonBox = nullptr; + d->m_account = acc; + d->m_split = s; + d->m_precision = 2; + d->m_amountValid = amountValid; + d->m_isDeposit = deposit; + d->m_calculatedValue = calculatedValue; + d->init(t, priceInfo); } KSplitTransactionDlg::~KSplitTransactionDlg() { - KConfigGroup grp = KSharedConfig::openConfig()->group("SplitTransactionEditor"); + Q_D(KSplitTransactionDlg); + auto grp = KSharedConfig::openConfig()->group("SplitTransactionEditor"); grp.writeEntry("Geometry", size()); + delete d; } int KSplitTransactionDlg::exec() { + Q_D(KSplitTransactionDlg); // for deposits, we invert the sign of all splits. // don't forget to revert when we're done ;-) - if (m_isDeposit) { - for (int i = 0; i < m_transaction.splits().count(); ++i) { - MyMoneySplit split = m_transaction.splits()[i]; + if (d->m_isDeposit) { + for (auto i = 0; i < d->m_transaction.splits().count(); ++i) { + MyMoneySplit split = d->m_transaction.splits()[i]; split.setValue(-split.value()); split.setShares(-split.shares()); - m_transaction.modifySplit(split); + d->m_transaction.modifySplit(split); } } int rc; do { - transactionsTable->setFocus(); + d->ui->transactionsTable->setFocus(); // initialize the display - transactionsTable->setTransaction(m_transaction, m_split, m_account); - updateSums(); + d->ui->transactionsTable->setTransaction(d->m_transaction, d->m_split, d->m_account); + d->updateSums(); - rc = KSplitTransactionDlgDecl::exec(); + rc = QDialog::exec(); if (rc == Accepted) { if (!diffAmount().isZero()) { - KSplitCorrectionDlgDecl* corrDlg = new KSplitCorrectionDlgDecl(this); - QVBoxLayout *mainLayout = new QVBoxLayout; - corrDlg->setLayout(mainLayout); - mainLayout->addWidget(corrDlg->findChild("verticalLayout")); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); - connect(buttonBox, SIGNAL(accepted()), corrDlg, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), corrDlg, SLOT(reject())); - mainLayout->addWidget(buttonBox); - corrDlg->buttonGroup->setId(corrDlg->continueBtn, 0); - corrDlg->buttonGroup->setId(corrDlg->changeBtn, 1); - corrDlg->buttonGroup->setId(corrDlg->distributeBtn, 2); - corrDlg->buttonGroup->setId(corrDlg->leaveBtn, 3); - - corrDlg->setModal(true); - - MyMoneySplit split = m_transaction.splits()[0]; - QString total = (-split.value()).formatMoney("", m_precision); - QString sums = splitsValue().formatMoney("", m_precision); - QString diff = diffAmount().formatMoney("", m_precision); + QPointer corrDlg = new KSplitCorrectionDlg(this); + connect(corrDlg->ui->buttonBox, &QDialogButtonBox::accepted, corrDlg.data(), &QDialog::accept); + connect(corrDlg->ui->buttonBox, &QDialogButtonBox::rejected, corrDlg.data(), &QDialog::reject); + corrDlg->ui->buttonGroup->setId(corrDlg->ui->continueBtn, 0); + corrDlg->ui->buttonGroup->setId(corrDlg->ui->changeBtn, 1); + corrDlg->ui->buttonGroup->setId(corrDlg->ui->distributeBtn, 2); + corrDlg->ui->buttonGroup->setId(corrDlg->ui->leaveBtn, 3); + + MyMoneySplit split = d->m_transaction.splits()[0]; + QString total = (-split.value()).formatMoney(QString(), d->m_precision); + QString sums = splitsValue().formatMoney(QString(), d->m_precision); + QString diff = diffAmount().formatMoney(QString(), d->m_precision); // now modify the text items of the dialog to contain the correct values QString q = i18n("The total amount of this transaction is %1 while " "the sum of the splits is %2. The remaining %3 are " "unassigned.", total, sums, diff); - corrDlg->explanation->setText(q); + corrDlg->ui->explanation->setText(q); q = i18n("Change &total amount of transaction to %1.", sums); - corrDlg->changeBtn->setText(q); + corrDlg->ui->changeBtn->setText(q); q = i18n("&Distribute difference of %1 among all splits.", diff); - corrDlg->distributeBtn->setText(q); + corrDlg->ui->distributeBtn->setText(q); // FIXME remove the following line once distribution among // all splits is implemented - corrDlg->distributeBtn->hide(); + corrDlg->ui->distributeBtn->hide(); // if we have only two splits left, we don't allow leaving sth. unassigned. - if (m_transaction.splitCount() < 3) { + if (d->m_transaction.splitCount() < 3) { q = i18n("&Leave total amount of transaction at %1.", total); } else { q = i18n("&Leave %1 unassigned.", diff); } - corrDlg->leaveBtn->setText(q); + corrDlg->ui->leaveBtn->setText(q); if ((rc = corrDlg->exec()) == Accepted) { - switch (corrDlg->buttonGroup->checkedId()) { + switch (corrDlg->ui->buttonGroup->checkedId()) { case 0: // continue to edit rc = Rejected; break; case 1: // modify total split.setValue(-splitsValue()); split.setShares(-splitsValue()); - m_transaction.modifySplit(split); + d->m_transaction.modifySplit(split); break; case 2: // distribute difference qDebug("distribution of difference not yet supported in KSplitTransactionDlg::slotFinishClicked()"); break; case 3: // leave unassigned break; } } delete corrDlg; } } else break; } while (rc != Accepted); // for deposits, we inverted the sign of all splits. // now we revert it back, so that things are left correct - if (m_isDeposit) { - for (int i = 0; i < m_transaction.splits().count(); ++i) { - MyMoneySplit split = m_transaction.splits()[i]; + if (d->m_isDeposit) { + for (auto i = 0; i < d->m_transaction.splits().count(); ++i) { + auto split = d->m_transaction.splits()[i]; split.setValue(-split.value()); split.setShares(-split.shares()); - m_transaction.modifySplit(split); + d->m_transaction.modifySplit(split); } } return rc; } void KSplitTransactionDlg::initSize() { QDialog::resize(width(), height() + 1); } void KSplitTransactionDlg::accept() { - transactionsTable->slotCancelEdit(); - KSplitTransactionDlgDecl::accept(); + Q_D(KSplitTransactionDlg); + d->ui->transactionsTable->slotCancelEdit(); + QDialog::accept(); } void KSplitTransactionDlg::reject() { + Q_D(KSplitTransactionDlg); // cancel any edit activity in the split register - transactionsTable->slotCancelEdit(); - KSplitTransactionDlgDecl::reject(); + d->ui->transactionsTable->slotCancelEdit(); + QDialog::reject(); } void KSplitTransactionDlg::slotClearAllSplits() { + Q_D(KSplitTransactionDlg); int answer; answer = KMessageBox::warningContinueCancel(this, i18n("You are about to delete all splits of this transaction. " "Do you really want to continue?"), - i18n("KMyMoney"), - KGuiItem(i18n("Continue")) - ); + i18n("KMyMoney")); if (answer == KMessageBox::Continue) { - transactionsTable->slotCancelEdit(); - QList list = transactionsTable->getSplits(m_transaction); + d->ui->transactionsTable->slotCancelEdit(); + QList list = d->ui->transactionsTable->getSplits(d->m_transaction); QList::ConstIterator it; // clear all but the one referencing the account for (it = list.constBegin(); it != list.constEnd(); ++it) { - m_transaction.removeSplit(*it); + d->m_transaction.removeSplit(*it); } - transactionsTable->setTransaction(m_transaction, m_split, m_account); - slotSetTransaction(m_transaction); + d->ui->transactionsTable->setTransaction(d->m_transaction, d->m_split, d->m_account); + slotSetTransaction(d->m_transaction); } } void KSplitTransactionDlg::slotClearUnusedSplits() { - QList list = transactionsTable->getSplits(m_transaction); + Q_D(KSplitTransactionDlg); + QList list = d->ui->transactionsTable->getSplits(d->m_transaction); QList::ConstIterator it; try { // remove all splits that don't have a value assigned for (it = list.constBegin(); it != list.constEnd(); ++it) { if ((*it).shares().isZero()) { - m_transaction.removeSplit(*it); + d->m_transaction.removeSplit(*it); } } - transactionsTable->setTransaction(m_transaction, m_split, m_account); - slotSetTransaction(m_transaction); + d->ui->transactionsTable->setTransaction(d->m_transaction, d->m_split, d->m_account); + slotSetTransaction(d->m_transaction); } catch (const MyMoneyException &) { } } void KSplitTransactionDlg::slotMergeSplits() { - QList list = transactionsTable->getSplits(m_transaction); + Q_D(KSplitTransactionDlg); + QList list = d->ui->transactionsTable->getSplits(d->m_transaction); QList::ConstIterator it; try { // collect all splits, merge them if needed and remove from transaction QList splits; for (it = list.constBegin(); it != list.constEnd(); ++it) { QList::iterator it_s; for (it_s = splits.begin(); it_s != splits.end(); ++it_s) { if ((*it_s).accountId() == (*it).accountId() && (*it_s).memo().isEmpty() && (*it).memo().isEmpty()) break; } if (it_s != splits.end()) { (*it_s).setShares((*it).shares() + (*it_s).shares()); (*it_s).setValue((*it).value() + (*it_s).value()); } else { splits << *it; } - m_transaction.removeSplit(*it); + d->m_transaction.removeSplit(*it); } // now add them back to the transaction QList::iterator it_s; for (it_s = splits.begin(); it_s != splits.end(); ++it_s) { (*it_s).clearId(); - m_transaction.addSplit(*it_s); + d->m_transaction.addSplit(*it_s); } - transactionsTable->setTransaction(m_transaction, m_split, m_account); - slotSetTransaction(m_transaction); + d->ui->transactionsTable->setTransaction(d->m_transaction, d->m_split, d->m_account); + slotSetTransaction(d->m_transaction); } catch (const MyMoneyException &) { } } void KSplitTransactionDlg::slotSetTransaction(const MyMoneyTransaction& t) { - m_transaction = t; + Q_D(KSplitTransactionDlg); + d->m_transaction = t; slotUpdateButtons(); - updateSums(); + d->updateSums(); } void KSplitTransactionDlg::slotUpdateButtons() { - QList list = transactionsTable->getSplits(m_transaction); + Q_D(KSplitTransactionDlg); + QList list = d->ui->transactionsTable->getSplits(d->m_transaction); // check if we can merge splits or not, have zero splits or not QMap splits; bool haveZeroSplit = false; for (QList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it) { splits[(*it).accountId()]++; - if (((*it).id() != m_split.id()) && ((*it).shares().isZero())) + if (((*it).id() != d->m_split.id()) && ((*it).shares().isZero())) haveZeroSplit = true; } QMap::const_iterator it_s; for (it_s = splits.constBegin(); it_s != splits.constEnd(); ++it_s) { if ((*it_s) > 1) break; } - m_buttonBox->buttons().at(4)->setEnabled(it_s != splits.constEnd()); - m_buttonBox->buttons().at(3)->setEnabled(haveZeroSplit); + d->ui->buttonBox->buttons().at(4)->setEnabled(it_s != splits.constEnd()); + d->ui->buttonBox->buttons().at(3)->setEnabled(haveZeroSplit); } void KSplitTransactionDlg::slotEditStarted() { - m_buttonBox->buttons().at(4)->setEnabled(false); - m_buttonBox->buttons().at(3)->setEnabled(false); -} - -void KSplitTransactionDlg::updateSums() -{ - MyMoneyMoney splits(splitsValue()); - - if (m_amountValid == false) { - m_split.setValue(-splits); - m_transaction.modifySplit(m_split); - } - - splitSum->setText("" + splits.formatMoney("", m_precision) + ' '); - splitUnassigned->setText("" + diffAmount().formatMoney("", m_precision) + ' '); - transactionAmount->setText("" + (-m_split.value()).formatMoney("", m_precision) + ' '); + Q_D(KSplitTransactionDlg); + d->ui->buttonBox->buttons().at(4)->setEnabled(false); + d->ui->buttonBox->buttons().at(3)->setEnabled(false); } MyMoneyMoney KSplitTransactionDlg::splitsValue() { - MyMoneyMoney splitsValue(m_calculatedValue); - QList list = transactionsTable->getSplits(m_transaction); + Q_D(KSplitTransactionDlg); + MyMoneyMoney splitsValue(d->m_calculatedValue); + QList list = d->ui->transactionsTable->getSplits(d->m_transaction); QList::ConstIterator it; // calculate the current sum of all split parts for (it = list.constBegin(); it != list.constEnd(); ++it) { if ((*it).value() != MyMoneyMoney::autoCalc) splitsValue += (*it).value(); } return splitsValue; } +MyMoneyTransaction KSplitTransactionDlg::transaction() const +{ + Q_D(const KSplitTransactionDlg); + return d->m_transaction; +} + MyMoneyMoney KSplitTransactionDlg::diffAmount() { + Q_D(KSplitTransactionDlg); MyMoneyMoney diff; // if there is an amount specified in the transaction, we need to calculate the // difference, otherwise we display the difference as 0 and display the same sum. - if (m_amountValid) { - MyMoneySplit split = m_transaction.splits()[0]; + if (d->m_amountValid) { + MyMoneySplit split = d->m_transaction.splits()[0]; diff = -(splitsValue() + split.value()); } return diff; } void KSplitTransactionDlg::slotCreateCategory(const QString& name, QString& id) { + Q_D(KSplitTransactionDlg); MyMoneyAccount acc, parent; acc.setName(name); - if (m_isDeposit) + if (d->m_isDeposit) parent = MyMoneyFile::instance()->income(); else parent = MyMoneyFile::instance()->expense(); // TODO extract possible first part of a hierarchy and check if it is one // of our top categories. If so, remove it and select the parent // according to this information. emit createCategory(acc, parent); // return id id = acc.id(); } diff --git a/kmymoney/dialogs/ksplittransactiondlg.h b/kmymoney/dialogs/ksplittransactiondlg.h index 51d80d438..8db9e89d3 100644 --- a/kmymoney/dialogs/ksplittransactiondlg.h +++ b/kmymoney/dialogs/ksplittransactiondlg.h @@ -1,195 +1,147 @@ /*************************************************************************** ksplittransactiondlg.h - description ------------------- begin : Thu Jan 10 2002 copyright : (C) 2000-2002 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSPLITTRANSACTIONDLG_H #define KSPLITTRANSACTIONDLG_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "mymoneymoney.h" -#include "mymoneyaccount.h" -#include "mymoneytransaction.h" - - -#include "ui_ksplittransactiondlgdecl.h" -#include "ui_ksplitcorrectiondlg.h" +class MyMoneyMoney; +class MyMoneySplit; +class MyMoneyTransaction; +class MyMoneyAccount; -class QDialogButtonBox; +namespace Ui { class KSplitCorrectionDlg; } -class KSplitCorrectionDlgDecl : public QDialog, public Ui::KSplitCorrectionDlgDecl +class KSplitCorrectionDlg : public QDialog { + Q_OBJECT + Q_DISABLE_COPY(KSplitCorrectionDlg) + public: - KSplitCorrectionDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } + explicit KSplitCorrectionDlg(QWidget *parent = nullptr); + ~KSplitCorrectionDlg(); + + Ui::KSplitCorrectionDlg *ui; }; /** * @author Thomas Baumgart */ -class KSplitTransactionDlgDecl : public QDialog, public Ui::KSplitTransactionDlgDecl -{ -public: - KSplitTransactionDlgDecl(QWidget *parent) : QDialog(parent), m_buttonBox(0) { - setupUi(this); - } - -protected: - QDialogButtonBox *m_buttonBox; -}; - -class KSplitTransactionDlg : public KSplitTransactionDlgDecl +class KSplitTransactionDlgPrivate; +class KSplitTransactionDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KSplitTransactionDlg) public: - KSplitTransactionDlg(const MyMoneyTransaction& t, - const MyMoneySplit& s, - const MyMoneyAccount& acc, - const bool amountValid, - const bool deposit, - const MyMoneyMoney& calculatedValue, - const QMap& priceInfo, - QWidget* parent = 0); + explicit KSplitTransactionDlg(const MyMoneyTransaction& t, + const MyMoneySplit& s, + const MyMoneyAccount& acc, + const bool amountValid, + const bool deposit, + const MyMoneyMoney& calculatedValue, + const QMap& priceInfo, + QWidget* parent = nullptr); - virtual ~KSplitTransactionDlg(); + ~KSplitTransactionDlg(); /** * Using this method, an external object can retrieve the result * of the dialog. * * @return MyMoneyTransaction based on the transaction passes during * the construction of this object and modified using the * dialog. */ - const MyMoneyTransaction& transaction() const { - return m_transaction; - }; + MyMoneyTransaction transaction() const; /** * This method calculates the difference between the split that references * the account passed as argument to the constructor of this object and * all the other splits shown in the register of this dialog. * * @return difference as MyMoneyMoney object */ MyMoneyMoney diffAmount(); /** * This method calculates the sum of the splits shown in the register * of this dialog. * * @return sum of splits as MyMoneyMoney object */ MyMoneyMoney splitsValue(); -private: - /** - * This method updates the display of the sums below the register - */ - void updateSums(); - public slots: - int exec(); + int exec() override; protected slots: - void accept(); - void reject(); + void accept() override; + void reject() override; void slotClearAllSplits(); void slotClearUnusedSplits(); void slotSetTransaction(const MyMoneyTransaction& t); void slotCreateCategory(const QString& txt, QString& id); void slotUpdateButtons(); void slotMergeSplits(); void slotEditStarted(); /// used internally to setup the initial size of all widgets void initSize(); signals: /** * This signal is sent out, when a new category needs to be created * Depending on the setting of either a payment or deposit, the parent * account will be preset to Expense or Income. * * @param account reference to account info. Will be filled by called slot * @param parent reference to parent account */ void createCategory(MyMoneyAccount& account, const MyMoneyAccount& parent); /** * Signal is emitted, if any of the widgets enters (@a state equals @a true) * or leaves (@a state equals @a false) object creation mode. * * @param state Enter (@a true) or leave (@a false) object creation */ void objectCreation(bool state); private: - /** - * This member keeps a copy of the current selected transaction - */ - MyMoneyTransaction m_transaction; - - /** - * This member keeps a copy of the currently selected account - */ - MyMoneyAccount m_account; - - /** - * This member keeps a copy of the currently selected split - */ - MyMoneySplit m_split; - - /** - * This member keeps the precision for the values - */ - int m_precision; - - /** - * flag that shows that the amount specified in the constructor - * should be used as fix value (true) or if it can be changed (false) - */ - bool m_amountValid; - - /** - * This member keeps track if the current transaction is of type - * deposit (true) or withdrawal (false). - */ - bool m_isDeposit; - - /** - * This member keeps the amount that will be assigned to all the - * splits that are marked 'will be calculated'. - */ - MyMoneyMoney m_calculatedValue; + KSplitTransactionDlgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KSplitTransactionDlg) }; #endif diff --git a/kmymoney/dialogs/ksplittransactiondlg.ui b/kmymoney/dialogs/ksplittransactiondlg.ui new file mode 100644 index 000000000..a105ebd81 --- /dev/null +++ b/kmymoney/dialogs/ksplittransactiondlg.ui @@ -0,0 +1,364 @@ + + + KSplitTransactionDlg + + + + 0 + 0 + 656 + 408 + + + + Split transaction + + + true + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + ArrowCursor + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 6 + + + 1 + + + 1 + + + 1 + + + 1 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 0 + 16 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + + + + 0 + 0 + + + + + 120 + 15 + + + + <b>11,00<b> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + + 120 + 15 + + + + <b>111,00<b> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 75 + true + + + + Unassigned + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 75 + true + + + + Sum of splits + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + + 120 + 15 + + + + 100,00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 150 + 0 + + + + + 75 + true + + + + Transaction amount + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + + + + 0 + 0 + + + + + 15 + 0 + + + + + 32767 + 80 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + + + + + + + + + Qt::Vertical + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + kMyMoneySplitTable + QWidget +
../dialogs/kmymoneysplittable.h
+
+
+ + + + buttonBox + accepted() + KSplitTransactionDlg + accept() + + + 607 + 203 + + + 327 + 203 + + + + + buttonBox + rejected() + KSplitTransactionDlg + reject() + + + 607 + 203 + + + 327 + 203 + + + + +
diff --git a/kmymoney/dialogs/ksplittransactiondlgdecl.ui b/kmymoney/dialogs/ksplittransactiondlgdecl.ui deleted file mode 100644 index f61d26707..000000000 --- a/kmymoney/dialogs/ksplittransactiondlgdecl.ui +++ /dev/null @@ -1,315 +0,0 @@ - - - - - - KSplitTransactionDlgDecl - - - - 0 - 0 - 656 - 408 - - - - Split transaction - - - true - - - - - 0 - 0 - - - - - 0 - - - 6 - - - - - 0 - - - 6 - - - - - 0 - - - - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 1 - - - 6 - - - - - - 0 - 16 - - - - QSizePolicy::Expanding - - - Qt::Horizontal - - - - - - - 0 - - - 1 - - - - - - 0 - 0 - 0 - 0 - - - - - 120 - 15 - - - - <b>11,00<b> - - - Qt::AlignVCenter|Qt::AlignRight - - - false - - - - - - - - 0 - 0 - 0 - 0 - - - - - 120 - 15 - - - - <b>111,00<b> - - - Qt::AlignVCenter|Qt::AlignRight - - - false - - - - - - - - true - - - - Unassigned - - - Qt::AlignVCenter|Qt::AlignRight - - - false - - - - - - - - true - - - - Sum of splits - - - Qt::AlignVCenter|Qt::AlignRight - - - false - - - - - - - - 0 - 0 - 0 - 0 - - - - - 120 - 15 - - - - 100,00 - - - Qt::AlignVCenter|Qt::AlignRight - - - false - - - - - - - - 150 - 0 - - - - - true - - - - Transaction amount - - - Qt::AlignVCenter|Qt::AlignRight - - - false - - - - - - - QFrame::HLine - - - QFrame::Sunken - - - - - - - - - - 5 - 3 - 0 - 0 - - - - - 15 - 0 - - - - - 32767 - 80 - - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - - - - - - - - - - QDialog - QDialog -
kdialog.h
-
- - kMyMoneySplitTable - QWidget -
../dialogs/kmymoneysplittable.h
- - 330 - 390 - - 0 - - 5 - 5 - - image0 -
-
- - - 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000000c749444154388dad55db1184200c4c180bb81a28c73aad811228c356f42b3792db3cc0db2fc724bb7901dc7b270f27ed17fa5fa9b117b7cd90211f4ba0ac906a7f1453b4d30ca917bb590681552af23f69bfc4ffa71519d2c8f62546ea5ea03738b1c18c33a4d156f0d13f43b61952e4af6d6e8fb3a408f080448419a433d6486d85052fdba892a295f5d45785cd8c51a9d6de6a814a8d2131da51f98e7a3b64ec9da04a8db53d43be3c3c0b22cacf17e4cdb5a931649ceddf34b190cf0aa019f03f1fd3e7457f03b5a66c9ed26e86130000000049454e44ae426082 - - -
diff --git a/kmymoney/dialogs/ktagreassigndlg.cpp b/kmymoney/dialogs/ktagreassigndlg.cpp index 34f1ea5ac..283c038af 100644 --- a/kmymoney/dialogs/ktagreassigndlg.cpp +++ b/kmymoney/dialogs/ktagreassigndlg.cpp @@ -1,75 +1,79 @@ /*************************************************************************** ktagreassigndlg.cpp ------------------- copyright : (C) 2011 by Alessandro Russo + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "ktagreassigndlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_ktagreassigndlg.h" #include KTagReassignDlg::KTagReassignDlg(QWidget* parent) : - KTagReassignDlgDecl(parent) + QDialog(parent), + ui(new Ui::KTagReassignDlg) { - kMandatoryFieldGroup* mandatory = new kMandatoryFieldGroup(this); - mandatory->add(tagCombo); - mandatory->setOkButton(buttonBox->button(QDialogButtonBox::Ok)); + ui->setupUi(this); + auto mandatory = new kMandatoryFieldGroup(this); + mandatory->add(ui->tagCombo); + mandatory->setOkButton(ui->buttonBox->button(QDialogButtonBox::Ok)); } KTagReassignDlg::~KTagReassignDlg() { + delete ui; } QString KTagReassignDlg::show(const QList& tagslist) { if (tagslist.isEmpty()) return QString(); // no tag available? nothing can be selected... - tagCombo->loadTags(tagslist); + ui->tagCombo->loadTags(tagslist); // execute dialog and if aborted, return empty string if (this->exec() == QDialog::Rejected) return QString(); // otherwise return index of selected tag - return tagCombo->selectedItem(); + return ui->tagCombo->selectedItem(); } - void KTagReassignDlg::accept() { - // force update of tagCombo - buttonBox->button(QDialogButtonBox::Ok)->setFocus(); + // force update of ui->tagCombo + ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); - if (tagCombo->selectedItem().isEmpty()) { + if (ui->tagCombo->selectedItem().isEmpty()) { KMessageBox::information(this, i18n("This dialog does not allow new tags to be created. Please pick a tag from the list."), i18n("Tag creation")); } else { - KTagReassignDlgDecl::accept(); + QDialog::accept(); } } diff --git a/kmymoney/dialogs/ktagreassigndlg.h b/kmymoney/dialogs/ktagreassigndlg.h index 4e5ba264d..47337de4d 100644 --- a/kmymoney/dialogs/ktagreassigndlg.h +++ b/kmymoney/dialogs/ktagreassigndlg.h @@ -1,73 +1,68 @@ /*************************************************************************** ktagreassigndlg.cpp ------------------- copyright : (C) 2012 by Alessandro Russo + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KTAGREASSIGNDLG_H #define KTAGREASSIGNDLG_H // ---------------------------------------------------------------------------- // QT Includes -#include +#include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ktagreassigndlgdecl.h" +namespace Ui { class KTagReassignDlg; } /** * Implementation of the dialog that lets the user select a tag in order * to re-assign transactions (for instance, if tags are deleted). */ class MyMoneyTag; -class KTagReassignDlgDecl : public QDialog, public Ui::KTagReassignDlgDecl -{ -public: - KTagReassignDlgDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; -class KTagReassignDlg : public KTagReassignDlgDecl +class KTagReassignDlg : public QDialog { Q_OBJECT -public: - /** Default constructor */ - KTagReassignDlg(QWidget* parent = 0); + Q_DISABLE_COPY(KTagReassignDlg) - /** Destructor */ +public: + explicit KTagReassignDlg(QWidget* parent = nullptr); ~KTagReassignDlg(); /** * This function sets up the dialog, lets the user select a tag and returns * the id of the selected tag in the tagslist. * * @param tagslist reference to QList of MyMoneyTag objects to be contained in the list * * @return Returns the id of the selected tag in the list or QString() if * the dialog was aborted. QString() is also returned if the tagslist is empty. */ QString show(const QList& tagslist); protected: - void accept(); + void accept() override; +private: + Ui::KTagReassignDlg *ui; }; #endif // KTAGREASSIGNDLG_H diff --git a/kmymoney/dialogs/ktagreassigndlgdecl.ui b/kmymoney/dialogs/ktagreassigndlg.ui similarity index 95% rename from kmymoney/dialogs/ktagreassigndlgdecl.ui rename to kmymoney/dialogs/ktagreassigndlg.ui index 4aa75cc66..8d25aeeb9 100644 --- a/kmymoney/dialogs/ktagreassigndlgdecl.ui +++ b/kmymoney/dialogs/ktagreassigndlg.ui @@ -1,150 +1,150 @@ - KTagReassignDlgDecl - + KTagReassignDlg + 0 0 558 312 Reassign tags false true 300 0 The transactions associated with the selected tags need to be re-assigned to a different tag before the selected tags can be deleted. Please select a tag from the list below. Qt::AlignJustify|Qt::AlignTop true Qt::Vertical QSizePolicy::Fixed 20 16 Available tags: false Qt::Vertical QSizePolicy::Expanding 20 20 QFrame::HLine QFrame::Sunken QDialogButtonBox::Cancel|QDialogButtonBox::Ok KMyMoneyTagCombo QWidget
kmymoneymvccombo.h
1
buttonBox accepted() - KTagReassignDlgDecl + KTagReassignDlg accept() 313 286 76 308 buttonBox rejected() - KTagReassignDlgDecl + KTagReassignDlg reject() 462 291 392 308
diff --git a/kmymoney/dialogs/ktemplateexportdlg.cpp b/kmymoney/dialogs/ktemplateexportdlg.cpp index 611a65425..513491a4b 100644 --- a/kmymoney/dialogs/ktemplateexportdlg.cpp +++ b/kmymoney/dialogs/ktemplateexportdlg.cpp @@ -1,45 +1,46 @@ /*************************************************************************** ktemplateexportlg.cpp --------------------- copyright : (C) 2016 by Ralf Habacker + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "ktemplateexportdlg.h" #include "ui_ktemplateexportdlg.h" KTemplateExportDlg::KTemplateExportDlg(QWidget *parent) : QDialog(parent), ui(new Ui::KTemplateExportDlg) { ui->setupUi(this); } KTemplateExportDlg::~KTemplateExportDlg() { delete ui; } QString KTemplateExportDlg::title() const { return ui->m_title->text(); } QString KTemplateExportDlg::shortDescription() const { return ui->m_shortDescription->text(); } QString KTemplateExportDlg::longDescription() const { return ui->m_longDescription->document()->toPlainText(); } diff --git a/kmymoney/dialogs/ktemplateexportdlg.h b/kmymoney/dialogs/ktemplateexportdlg.h index 1b55c74f3..1a8badc3b 100644 --- a/kmymoney/dialogs/ktemplateexportdlg.h +++ b/kmymoney/dialogs/ktemplateexportdlg.h @@ -1,42 +1,43 @@ /*************************************************************************** ktemplateexportlg.cpp --------------------- copyright : (C) 2016 by Ralf Habacker + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KTEMPLATEEXPORTDLG_H #define KTEMPLATEEXPORTDLG_H #include namespace Ui { class KTemplateExportDlg; } class KTemplateExportDlg : public QDialog { Q_OBJECT public: - explicit KTemplateExportDlg(QWidget *parent = 0); + explicit KTemplateExportDlg(QWidget *parent = nullptr); ~KTemplateExportDlg(); QString title() const; QString shortDescription() const; QString longDescription() const; private: Ui::KTemplateExportDlg *ui; }; #endif // KTEMPLATEEXPORTDLG_H diff --git a/kmymoney/dialogs/ktemplateexportdlg.ui b/kmymoney/dialogs/ktemplateexportdlg.ui index 916d724f4..b52fb5694 100644 --- a/kmymoney/dialogs/ktemplateexportdlg.ui +++ b/kmymoney/dialogs/ktemplateexportdlg.ui @@ -1,100 +1,106 @@ KTemplateExportDlg 0 0 397 - 282 + 284 Template Export Attributes + + + Short description Long Description Title Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - + + + KTextEdit + QTextEdit +
ktextedit.h
+
+
m_title m_shortDescription - m_longDescription buttonBox buttonBox accepted() KTemplateExportDlg accept() 248 254 157 274 buttonBox rejected() KTemplateExportDlg reject() 316 260 286 274
diff --git a/kmymoney/dialogs/kupdatestockpricedlg.cpp b/kmymoney/dialogs/kupdatestockpricedlg.cpp index d58b5404f..0117b13d9 100644 --- a/kmymoney/dialogs/kupdatestockpricedlg.cpp +++ b/kmymoney/dialogs/kupdatestockpricedlg.cpp @@ -1,75 +1,88 @@ /*************************************************************************** kupdatestockpricedlg.cpp - description ------------------- begin : Thu Feb 7 2002 copyright : (C) 2000-2002 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "kupdatestockpricedlg.h" // ---------------------------------------------------------------------------- // QT Includes +#include +#include + // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes +#include "ui_kupdatestockpricedlg.h" + +#include "kmymoneydateinput.h" #include "kmymoneycurrencyselector.h" KUpdateStockPriceDlg::KUpdateStockPriceDlg(QWidget* parent) : - kUpdateStockPriceDecl(parent) + QDialog(parent), + ui(new Ui::KUpdateStockPriceDlg) { + ui->setupUi(this); setModal(true); - m_date->setDate(QDate::currentDate()); - init(); + ui->m_date->setDate(QDate::currentDate()); + + connect(ui->m_security, static_cast(&QComboBox::activated), this, static_cast(&KUpdateStockPriceDlg::slotCheckData)); + connect(ui->m_currency, static_cast(&QComboBox::activated), this, static_cast(&KUpdateStockPriceDlg::slotCheckData)); + + // load initial values into the selection widgets + ui->m_currency->update(QString()); + ui->m_security->update(QString()); + + slotCheckData(); } KUpdateStockPriceDlg::~KUpdateStockPriceDlg() { + delete ui; } -void KUpdateStockPriceDlg::init() +int KUpdateStockPriceDlg::exec() { - connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - - connect(m_security, SIGNAL(activated(int)), this, SLOT(slotCheckData())); - connect(m_currency, SIGNAL(activated(int)), this, SLOT(slotCheckData())); - - // load initial values into the selection widgets - m_currency->update(QString()); - m_security->update(QString()); - slotCheckData(); + return QDialog::exec(); } -int KUpdateStockPriceDlg::exec() +QDate KUpdateStockPriceDlg::date() const { - slotCheckData(); - return kUpdateStockPriceDecl::exec(); + return ui->m_date->date(); } void KUpdateStockPriceDlg::slotCheckData() { - QString from = m_security->security().id(); - QString to = m_currency->security().id(); + auto from = ui->m_security->security().id(); + auto to = ui->m_currency->security().id(); - m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!from.isEmpty() && !to.isEmpty() && from != to); + ui->m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!from.isEmpty() && !to.isEmpty() && from != to); +} + +void KUpdateStockPriceDlg::slotCheckData(int) +{ + slotCheckData(); } diff --git a/kmymoney/dialogs/kupdatestockpricedlg.h b/kmymoney/dialogs/kupdatestockpricedlg.h index 32ed7d685..fc58d4f5d 100644 --- a/kmymoney/dialogs/kupdatestockpricedlg.h +++ b/kmymoney/dialogs/kupdatestockpricedlg.h @@ -1,80 +1,71 @@ /*************************************************************************** kupdatestockpricedlg.h - description ------------------- begin : Thu Feb 7 2002 copyright : (C) 2000-2002 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KUPDATESTOCKPRICEDLG_H #define KUPDATESTOCKPRICEDLG_H // ---------------------------------------------------------------------------- // QT Includes -#include -#include +#include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_kupdatestockpricedlgdecl.h" +namespace Ui { class KUpdateStockPriceDlg; } -#include "mymoneyprice.h" -#include "kmymoneydateinput.h" -#include "kmymoneyedit.h" +class QDate; + +class MyMoneyMoney; /** * @author Kevin Tambascio */ -class kUpdateStockPriceDecl : public QDialog, public Ui::kUpdateStockPriceDecl -{ -public: - kUpdateStockPriceDecl(QWidget *parent) : QDialog(parent) { - setupUi(this); - } -}; -class KUpdateStockPriceDlg : public kUpdateStockPriceDecl +class KUpdateStockPriceDlg : public QDialog { Q_OBJECT + Q_DISABLE_COPY(KUpdateStockPriceDlg) public: - KUpdateStockPriceDlg(QWidget* parent = 0); + explicit KUpdateStockPriceDlg(QWidget* parent = nullptr); ~KUpdateStockPriceDlg(); - const QDate date() const { - return m_date->date(); - }; - const MyMoneyMoney price() const; + QDate date() const; + MyMoneyMoney price() const; + + Ui::KUpdateStockPriceDlg *ui; public slots: - int exec(); + int exec() override; protected slots: void slotCheckData(); - -private: - void init(); - + void slotCheckData(int idx); }; #endif diff --git a/kmymoney/dialogs/kupdatestockpricedlgdecl.ui b/kmymoney/dialogs/kupdatestockpricedlg.ui similarity index 86% rename from kmymoney/dialogs/kupdatestockpricedlgdecl.ui rename to kmymoney/dialogs/kupdatestockpricedlg.ui index bc108071e..5c1e6fa5b 100644 --- a/kmymoney/dialogs/kupdatestockpricedlgdecl.ui +++ b/kmymoney/dialogs/kupdatestockpricedlg.ui @@ -1,191 +1,224 @@ - kUpdateStockPriceDecl - + KUpdateStockPriceDlg + 0 0 457 194 New price entry Qt::Horizontal QSizePolicy::Expanding 71 21 0 0 Qt::Horizontal QSizePolicy::Expanding 40 20 Currency false Date: false Security false 0 0 Qt::Horizontal QSizePolicy::Expanding 40 20 Qt::Vertical QSizePolicy::Expanding 31 40 QFrame::HLine QFrame::Sunken QDialogButtonBox::Cancel|QDialogButtonBox::Ok KComboBox QComboBox
kcombobox.h
kMyMoneyDateInput QWidget
kmymoneydateinput.h
1
KMyMoneySecuritySelector KComboBox
kmymoneycurrencyselector.h
1
- + + + m_buttonBox + accepted() + KUpdateStockPriceDlg + accept() + + + 228 + 170 + + + 228 + 96 + + + + + m_buttonBox + rejected() + KUpdateStockPriceDlg + reject() + + + 228 + 170 + + + 228 + 96 + + + +
diff --git a/kmymoney/dialogs/settings/CMakeLists.txt b/kmymoney/dialogs/settings/CMakeLists.txt index 364a1dd49..31217d941 100644 --- a/kmymoney/dialogs/settings/CMakeLists.txt +++ b/kmymoney/dialogs/settings/CMakeLists.txt @@ -1,53 +1,53 @@ set (libsettings_a_SOURCES ksettingscolors.cpp ksettingsfonts.cpp ksettingsicons.cpp ksettingsforecast.cpp ksettingsgeneral.cpp ksettingsgpg.cpp ksettingshome.cpp ksettingsonlinequotes.cpp ksettingsregister.cpp ksettingsschedules.cpp ksettingsreports.cpp ksettingskmymoney.cpp ) set (libsettings_a_UI ksettingscolors.ui - ksettingsfontsdecl.ui - ksettingsiconsdecl.ui - ksettingsforecastdecl.ui - ksettingsgeneraldecl.ui - ksettingsgpgdecl.ui - ksettingshomedecl.ui - ksettingsonlinequotesdecl.ui - ksettingsregisterdecl.ui - ksettingsschedulesdecl.ui - ksettingsreportsdecl.ui + ksettingsfonts.ui + ksettingsicons.ui + ksettingsforecast.ui + ksettingsgeneral.ui + ksettingsgpg.ui + ksettingshome.ui + ksettingsonlinequotes.ui + ksettingsregister.ui + ksettingsschedules.ui + ksettingsreports.ui ) ki18n_wrap_ui(libsettings_a_SOURCES ${libsettings_a_UI} ) add_library(settings STATIC ${libsettings_a_SOURCES}) # TODO: cleanup dependencies target_link_libraries(settings PUBLIC KF5::Completion KF5::KIOWidgets KF5::TextWidgets KF5::I18n KF5::IconThemes KF5::Completion KF5::KCMUtils KF5::ItemViews Alkimia::alkimia Qt5::Sql ) if (KF5Holidays_FOUND) target_link_libraries(settings PUBLIC KF5::Holidays) endif() add_dependencies(settings widgets kmm_config) diff --git a/kmymoney/dialogs/settings/ksettingscolors.cpp b/kmymoney/dialogs/settings/ksettingscolors.cpp index 657427f37..f3fa07233 100644 --- a/kmymoney/dialogs/settings/ksettingscolors.cpp +++ b/kmymoney/dialogs/settings/ksettingscolors.cpp @@ -1,49 +1,53 @@ /*************************************************************************** ksettingscolors.cpp -------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net (C) 2017 by Ł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. * * * ***************************************************************************/ #include "ksettingscolors.h" #include "kmymoneyglobalsettings.h" // ---------------------------------------------------------------------------- // QT Includes // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes +#include "ui_ksettingscolors.h" + KSettingsColors::KSettingsColors(QWidget* parent) : - QWidget(parent) + QWidget(parent), + ui(new Ui::KSettingsColors) { - setupUi(this); - connect(kcfg_useCustomColors, &QGroupBox::toggled, this, &KSettingsColors::slotCustomColorsToggled); + ui->setupUi(this); + connect(ui->kcfg_useCustomColors, &QGroupBox::toggled, this, &KSettingsColors::slotCustomColorsToggled); } KSettingsColors::~KSettingsColors() { + delete ui; } void KSettingsColors::slotCustomColorsToggled(bool) { - kcfg_transactionErroneousColor->setColor(KMyMoneyGlobalSettings::schemeColor(SchemeColor::TransactionErroneous)); - kcfg_missingConversionRateColor->setColor(KMyMoneyGlobalSettings::schemeColor(SchemeColor::MissingConversionRate)); - kcfg_groupMarkerColor->setColor(KMyMoneyGlobalSettings::schemeColor(SchemeColor::GroupMarker)); - kcfg_fieldRequiredColor->setColor(KMyMoneyGlobalSettings::schemeColor(SchemeColor::FieldRequired)); - kcfg_transactionImportedColor->setColor(KMyMoneyGlobalSettings::schemeColor(SchemeColor::TransactionImported)); - kcfg_transactionMatchedColor->setColor(KMyMoneyGlobalSettings::schemeColor(SchemeColor::TransactionMatched)); + ui->kcfg_transactionErroneousColor->setColor(KMyMoneyGlobalSettings::schemeColor(SchemeColor::TransactionErroneous)); + ui->kcfg_missingConversionRateColor->setColor(KMyMoneyGlobalSettings::schemeColor(SchemeColor::MissingConversionRate)); + ui->kcfg_groupMarkerColor->setColor(KMyMoneyGlobalSettings::schemeColor(SchemeColor::GroupMarker)); + ui->kcfg_fieldRequiredColor->setColor(KMyMoneyGlobalSettings::schemeColor(SchemeColor::FieldRequired)); + ui->kcfg_transactionImportedColor->setColor(KMyMoneyGlobalSettings::schemeColor(SchemeColor::TransactionImported)); + ui->kcfg_transactionMatchedColor->setColor(KMyMoneyGlobalSettings::schemeColor(SchemeColor::TransactionMatched)); } diff --git a/kmymoney/dialogs/settings/ksettingscolors.h b/kmymoney/dialogs/settings/ksettingscolors.h index 2c18632b8..9cdde1d4b 100644 --- a/kmymoney/dialogs/settings/ksettingscolors.h +++ b/kmymoney/dialogs/settings/ksettingscolors.h @@ -1,47 +1,53 @@ /*************************************************************************** ksettingscolors.h ------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSETTINGSCOLORS_H #define KSETTINGSCOLORS_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ksettingscolors.h" +namespace Ui { class KSettingsColors; } -class KSettingsColors : public QWidget, public Ui::KSettingsColors +class KSettingsColors : public QWidget { Q_OBJECT + Q_DISABLE_COPY(KSettingsColors) public: explicit KSettingsColors(QWidget* parent = nullptr); ~KSettingsColors(); private slots: /** * This presets custom colors with system's color scheme */ void slotCustomColorsToggled(bool); + +private: + Ui::KSettingsColors *ui; }; #endif diff --git a/kmymoney/dialogs/settings/ksettingsfonts.cpp b/kmymoney/dialogs/settings/ksettingsfonts.cpp index e3e3c817a..abf43f440 100644 --- a/kmymoney/dialogs/settings/ksettingsfonts.cpp +++ b/kmymoney/dialogs/settings/ksettingsfonts.cpp @@ -1,35 +1,41 @@ /*************************************************************************** ksettingsfonts.cpp -------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "ksettingsfonts.h" // ---------------------------------------------------------------------------- // QT Includes // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes +#include "ui_ksettingsfonts.h" + KSettingsFonts::KSettingsFonts(QWidget* parent) : - KSettingsFontsDecl(parent) + QWidget(parent), + ui(new Ui::KSettingsFonts) { + ui->setupUi(this); } KSettingsFonts::~KSettingsFonts() { + delete ui; } diff --git a/kmymoney/dialogs/settings/ksettingsfonts.h b/kmymoney/dialogs/settings/ksettingsfonts.h index a1070d4a8..26c368684 100644 --- a/kmymoney/dialogs/settings/ksettingsfonts.h +++ b/kmymoney/dialogs/settings/ksettingsfonts.h @@ -1,48 +1,47 @@ /*************************************************************************** ksettingsfonts.h ------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSETTINGSFONTS_H #define KSETTINGSFONTS_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ksettingsfontsdecl.h" - -class KSettingsFontsDecl : public QWidget, public Ui::KSettingsFontsDecl -{ -public: - KSettingsFontsDecl(QWidget *parent) : QWidget(parent) { - setupUi(this); - } -}; +namespace Ui { class KSettingsFonts; } -class KSettingsFonts : public KSettingsFontsDecl +class KSettingsFonts : public QWidget { Q_OBJECT + Q_DISABLE_COPY(KSettingsFonts) public: - KSettingsFonts(QWidget* parent = 0); + explicit KSettingsFonts(QWidget* parent = nullptr); ~KSettingsFonts(); + +private: + Ui::KSettingsFonts *ui; }; #endif diff --git a/kmymoney/dialogs/settings/ksettingsfontsdecl.ui b/kmymoney/dialogs/settings/ksettingsfonts.ui similarity index 97% rename from kmymoney/dialogs/settings/ksettingsfontsdecl.ui rename to kmymoney/dialogs/settings/ksettingsfonts.ui index a1ced50b3..b174fd219 100644 --- a/kmymoney/dialogs/settings/ksettingsfontsdecl.ui +++ b/kmymoney/dialogs/settings/ksettingsfonts.ui @@ -1,121 +1,121 @@ - KSettingsFontsDecl - + KSettingsFonts + 0 0 398 222 Font settings Use system fonts Individual font settings 110 20 QSizePolicy::Expanding Qt::Horizontal 100 20 QSizePolicy::Expanding Qt::Horizontal Cell font false Header font false 20 30 QSizePolicy::Expanding Qt::Vertical kcfg_useSystemFont toggled(bool) m_individualFontsFrame setDisabled(bool) diff --git a/kmymoney/dialogs/settings/ksettingsforecast.cpp b/kmymoney/dialogs/settings/ksettingsforecast.cpp index 11f5e5580..f4e2cd62c 100644 --- a/kmymoney/dialogs/settings/ksettingsforecast.cpp +++ b/kmymoney/dialogs/settings/ksettingsforecast.cpp @@ -1,35 +1,41 @@ /*************************************************************************** ksettingsforecast.cpp -------------------- copyright : (C) 2007 by Alvaro Soliverez email : asoliverez@gmail.com + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "ksettingsforecast.h" // ---------------------------------------------------------------------------- // QT Includes // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes +#include "ui_ksettingsforecast.h" + KSettingsForecast::KSettingsForecast(QWidget* parent) : - KSettingsForecastDecl(parent) + QWidget(parent), + ui(new Ui::KSettingsForecast) { + ui->setupUi(this); } KSettingsForecast::~KSettingsForecast() { + delete ui; } diff --git a/kmymoney/dialogs/settings/ksettingsforecast.h b/kmymoney/dialogs/settings/ksettingsforecast.h index ea7c441ed..fd96f9594 100644 --- a/kmymoney/dialogs/settings/ksettingsforecast.h +++ b/kmymoney/dialogs/settings/ksettingsforecast.h @@ -1,50 +1,47 @@ /*************************************************************************** ksettingsforecast.h ------------------- copyright : (C) 2007 by Alvaro Soliverez email : asoliverez@gmail.com + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSETTINGSFORECAST_H #define KSETTINGSFORECAST_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes - // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ksettingsforecastdecl.h" - -class KSettingsForecastDecl : public QWidget, public Ui::KSettingsForecastDecl -{ -public: - KSettingsForecastDecl(QWidget *parent) : QWidget(parent) { - setupUi(this); - } -}; - +namespace Ui { class KSettingsForecast; } -class KSettingsForecast : public KSettingsForecastDecl +class KSettingsForecast : public QWidget { Q_OBJECT + Q_DISABLE_COPY(KSettingsForecast) public: - KSettingsForecast(QWidget* parent = 0); + explicit KSettingsForecast(QWidget* parent = nullptr); ~KSettingsForecast(); + +private: + Ui::KSettingsForecast *ui; }; #endif diff --git a/kmymoney/dialogs/settings/ksettingsforecastdecl.ui b/kmymoney/dialogs/settings/ksettingsforecast.ui similarity index 98% rename from kmymoney/dialogs/settings/ksettingsforecastdecl.ui rename to kmymoney/dialogs/settings/ksettingsforecast.ui index 514c273fc..c71b62f22 100644 --- a/kmymoney/dialogs/settings/ksettingsforecastdecl.ui +++ b/kmymoney/dialogs/settings/ksettingsforecast.ui @@ -1,214 +1,214 @@ - KSettingsForecastDecl - + KSettingsForecast + 0 0 497 379 Forecast Settings 5 5 0 0 Number of Days of Account Cycle: false Day of Month to start Forecast: false Number of Days to Forecast: false 133 21 QSizePolicy::Expanding Qt::Horizontal Forecast Method Scheduled and Future Transactions History-based History-based settings Number of Cycles to use in Forecast: false 130 21 QSizePolicy::Expanding Qt::Horizontal History Forecast Method Simple Moving Average Weighted Moving Average Linear Regression 20 40 QSizePolicy::Expanding Qt::Vertical diff --git a/kmymoney/dialogs/settings/ksettingsgeneral.cpp b/kmymoney/dialogs/settings/ksettingsgeneral.cpp index 22b59541c..7c0eb2373 100644 --- a/kmymoney/dialogs/settings/ksettingsgeneral.cpp +++ b/kmymoney/dialogs/settings/ksettingsgeneral.cpp @@ -1,113 +1,143 @@ /*************************************************************************** ksettingsgeneral.cpp -------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "ksettingsgeneral.h" // ---------------------------------------------------------------------------- // QT Includes -#include #include -#include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes +#include "ui_ksettingsgeneral.h" + #include "kmymoneydateinput.h" #include "models.h" #include "accountsmodel.h" #include "mymoneymoney.h" #include "mymoneyfile.h" #include "mymoneyaccount.h" +class KSettingsGeneralPrivate +{ + Q_DISABLE_COPY(KSettingsGeneralPrivate) + +public: + KSettingsGeneralPrivate() : + ui(new Ui::KSettingsGeneral) + { + } + + ~KSettingsGeneralPrivate() + { + delete ui; + } + + Ui::KSettingsGeneral *ui; + bool initialHideZeroBalanceEquities; +}; + KSettingsGeneral::KSettingsGeneral(QWidget* parent) : - KSettingsGeneralDecl(parent) + QWidget(parent), + d_ptr(new KSettingsGeneralPrivate) { + Q_D(KSettingsGeneral); + d->ui->setupUi(this); // hide the internally used date field - kcfg_StartDate->hide(); + d->ui->kcfg_StartDate->hide(); // setup connections, so that the sort optios get loaded once the edit fields are filled - connect(kcfg_StartDate, SIGNAL(dateChanged(QDate)), this, SLOT(slotLoadStartDate(QDate))); + connect(d->ui->kcfg_StartDate, &QDateTimeEdit::dateChanged, this, &KSettingsGeneral::slotLoadStartDate); // setup connections, so that changes by the user are forwarded to the (hidden) edit fields - connect(m_startDateEdit, SIGNAL(dateChanged(QDate)), kcfg_StartDate, SLOT(setDate(QDate))); + connect(d->ui->m_startDateEdit, &kMyMoneyDateInput::dateChanged, d->ui->kcfg_StartDate, &QDateTimeEdit::setDate); - connect(choosePath, SIGNAL(pressed()), this, SLOT(slotChooseLogPath())); - initialHideZeroBalanceEquities = kcfg_HideZeroBalanceEquities->isChecked(); + connect(d->ui->choosePath, &QAbstractButton::pressed, this, &KSettingsGeneral::slotChooseLogPath); + d->initialHideZeroBalanceEquities = d->ui->kcfg_HideZeroBalanceEquities->isChecked(); } KSettingsGeneral::~KSettingsGeneral() { + Q_D(KSettingsGeneral); + delete d; } void KSettingsGeneral::slotChooseLogPath() { + Q_D(KSettingsGeneral); QString filePath = QFileDialog::getExistingDirectory(this, i18n("Choose file path"), QDir::homePath()); - kcfg_logPath->setText(filePath); + d->ui->kcfg_logPath->setText(filePath); slotUpdateLogTypes(); } void KSettingsGeneral::slotLoadStartDate(const QDate&) { + Q_D(KSettingsGeneral); // only need this once - disconnect(kcfg_StartDate, SIGNAL(dateChanged(QDate)), this, SLOT(slotLoadStartDate(QDate))); - m_startDateEdit->setDate(kcfg_StartDate->date()); + disconnect(d->ui->kcfg_StartDate, &QDateTimeEdit::dateChanged, this, &KSettingsGeneral::slotLoadStartDate); + d->ui->m_startDateEdit->setDate(d->ui->kcfg_StartDate->date()); } void KSettingsGeneral::slotUpdateLogTypes() { - bool enable = kcfg_logPath->text().isEmpty() ? false : true; - kcfg_logImportedStatements->setEnabled(enable); - kcfg_logOfxTransactions->setEnabled(enable); + Q_D(KSettingsGeneral); + bool enable = d->ui->kcfg_logPath->text().isEmpty() ? false : true; + d->ui->kcfg_logImportedStatements->setEnabled(enable); + d->ui->kcfg_logOfxTransactions->setEnabled(enable); if (!enable) { - kcfg_logImportedStatements->setChecked(enable); - kcfg_logOfxTransactions->setChecked(enable); + d->ui->kcfg_logImportedStatements->setChecked(enable); + d->ui->kcfg_logOfxTransactions->setChecked(enable); } } void KSettingsGeneral::showEvent(QShowEvent *event) { - KSettingsGeneralDecl::showEvent(event); + Q_UNUSED(event) + QWidget::showEvent(event); slotUpdateLogTypes(); } void KSettingsGeneral::slotUpdateEquitiesVisibility() { - if (initialHideZeroBalanceEquities == kcfg_HideZeroBalanceEquities->isChecked()) // setting hasn't been changed, so return + Q_D(KSettingsGeneral); + if (d->initialHideZeroBalanceEquities == d->ui->kcfg_HideZeroBalanceEquities->isChecked()) // setting hasn't been changed, so return return; - initialHideZeroBalanceEquities = kcfg_HideZeroBalanceEquities->isChecked(); + d->initialHideZeroBalanceEquities = d->ui->kcfg_HideZeroBalanceEquities->isChecked(); AccountsModel* accountsModel = Models::instance()->accountsModel(); // items' model for accounts' page InstitutionsModel* institutionsModel = Models::instance()->institutionsModel(); // items' model for institutions' page - MyMoneyFile *file = MyMoneyFile::instance(); + auto file = MyMoneyFile::instance(); QList accountsList; file->accountList(accountsList); foreach (const auto account, accountsList) { if (account.isInvest() && account.balance().isZero()) { // search only for zero balance stocks - if (initialHideZeroBalanceEquities) { + if (d->initialHideZeroBalanceEquities) { accountsModel->slotObjectRemoved(eMyMoney::File::Object::Account, account.id()); // remove item from accounts' page institutionsModel->slotObjectRemoved(eMyMoney::File::Object::Account, account.id()); // remove item from institutions' page } else { accountsModel->slotObjectAdded(eMyMoney::File::Object::Account, dynamic_cast(&account)); // add item to accounts' page institutionsModel->slotObjectAdded(eMyMoney::File::Object::Account, dynamic_cast(&account)); // add item to institutions' page } } } } diff --git a/kmymoney/dialogs/settings/ksettingsgeneral.h b/kmymoney/dialogs/settings/ksettingsgeneral.h index 3dd741243..6d0290987 100644 --- a/kmymoney/dialogs/settings/ksettingsgeneral.h +++ b/kmymoney/dialogs/settings/ksettingsgeneral.h @@ -1,60 +1,58 @@ /*************************************************************************** ksettingsgeneral.h ------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSETTINGSGENERAL_H #define KSETTINGSGENERAL_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ksettingsgeneraldecl.h" - -class KSettingsGeneralDecl : public QWidget, public Ui::KSettingsGeneralDecl -{ -public: - KSettingsGeneralDecl(QWidget *parent) : QWidget(parent) { - setupUi(this); - } -}; - -class KSettingsGeneral : public KSettingsGeneralDecl +class KSettingsGeneralPrivate; +class KSettingsGeneral : public QWidget { Q_OBJECT -private: - bool initialHideZeroBalanceEquities; + Q_DISABLE_COPY(KSettingsGeneral) + public: - KSettingsGeneral(QWidget* parent = 0); + explicit KSettingsGeneral(QWidget* parent = nullptr); ~KSettingsGeneral(); protected slots: void slotChooseLogPath(); void slotLoadStartDate(const QDate&); void slotUpdateLogTypes(); protected: - void showEvent(QShowEvent* event); + void showEvent(QShowEvent* event) override; public slots: void slotUpdateEquitiesVisibility(); + +private: + KSettingsGeneralPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KSettingsGeneral) }; #endif diff --git a/kmymoney/dialogs/settings/ksettingsgeneraldecl.ui b/kmymoney/dialogs/settings/ksettingsgeneral.ui similarity index 99% rename from kmymoney/dialogs/settings/ksettingsgeneraldecl.ui rename to kmymoney/dialogs/settings/ksettingsgeneral.ui index ecf00e438..cdf64c162 100644 --- a/kmymoney/dialogs/settings/ksettingsgeneraldecl.ui +++ b/kmymoney/dialogs/settings/ksettingsgeneral.ui @@ -1,709 +1,709 @@ - KSettingsGeneralDecl - + KSettingsGeneral + 0 0 600 499 General Settings 3 Global Startup options Show splash screen Autosave options Autosave periodically false 60 minutes false Qt::Horizontal QSizePolicy::Expanding 308 22 Autosave when file is modified upon close Setup number of backups to keep (local file only) Whenever the current data is saved into a local file, KMyMoney keeps the selected number of previous states of the file. Set it to 0 to turn the feature off. true Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 20 1 Number of backups to keep (0=off) Qt::Horizontal 40 20 Fiscal Year Your fiscal year starts on false 366 January February March April May June July August September October November December Qt::Horizontal QSizePolicy::Expanding 282 17 External programs Calculator Qt::Vertical QSizePolicy::Expanding 20 20 Views Startup page options Start with ho&mepage true Start with last selected view Type of the KMyMoney view List true Tree Tabbed Show title bar on each page Synchronize account selection of ledger and investment view Qt::Vertical QSizePolicy::Expanding 20 319 Filter Accounts / Categories This option hides all categories in the categories view that are not used in at least a single transaction. They are still shown in the category selection lists. Do not show unused categories This option hides all accounts that have been closed by the user in views and selection lists. You can use <b>View/Show all accounts</b> to temporarily show hidden accounts in the views. Do not show closed accounts Show equity accounts This option will display the categories in the accounts view also. Show categories in the accounts list view Do not show zero balance equities Schedules This option hides all finished schedules in the schedules view. Do not show finished schedules Transactions Do not show transactions prior to false Qt::Horizontal QSizePolicy::Expanding 63 20 This option hides all reconciled transactions in the ledger view. Do not show reconciled transactions Qt::Vertical QSizePolicy::Expanding 20 30 Support Logging Log path true 0 0 32 32 ... Qt::Horizontal 40 20 On choosing a log file path please keep in mind that log files may contain sensitive data (e.g. passwords in clear-text etc). true Log imported statements Log OFX transactions Qt::Vertical 20 255 Qt::Vertical 20 40 KComboBox QComboBox
kcombobox.h
KLineEdit QLineEdit
klineedit.h
kMyMoneyDateInput QFrame
kmymoneydateinput.h
1
kcfg_AutoSaveFile toggled(bool) m_periodFrame setEnabled(bool) 103 274 188 263
diff --git a/kmymoney/dialogs/settings/ksettingsgpg.cpp b/kmymoney/dialogs/settings/ksettingsgpg.cpp index 322864235..f15714f91 100644 --- a/kmymoney/dialogs/settings/ksettingsgpg.cpp +++ b/kmymoney/dialogs/settings/ksettingsgpg.cpp @@ -1,197 +1,235 @@ /*************************************************************************** ksettingsgpg.cpp -------------------- copyright : (C) 2005, 2008 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "ksettingsgpg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_ksettingsgpg.h" + #include #define RECOVER_KEY_ID "0xD2B08440" #define RECOVER_KEY_ID_FULL "59B0F826D2B08440" -KSettingsGpg::KSettingsGpg(QWidget* parent) : - KSettingsGpgDecl(parent), +class KSettingsGpgPrivate +{ + Q_DISABLE_COPY(KSettingsGpgPrivate) + +public: + KSettingsGpgPrivate() : + ui(new Ui::KSettingsGpg), m_checkCount(0), m_needCheckList(true), m_listOk(false) + { + } + + ~KSettingsGpgPrivate() + { + delete ui; + } + + Ui::KSettingsGpg *ui; + int m_checkCount; + bool m_needCheckList; + bool m_listOk; +}; + +KSettingsGpg::KSettingsGpg(QWidget* parent) : + QWidget(parent), + d_ptr(new KSettingsGpgPrivate) { + Q_D(KSettingsGpg); + d->ui->setupUi(this); setEnabled(KGPGFile::GPGAvailable()); // don't show the widget in which the master key is actually kept - kcfg_GpgRecipient->hide(); + d->ui->kcfg_GpgRecipient->hide(); - connect(kcfg_WriteDataEncrypted, SIGNAL(toggled(bool)), this, SLOT(slotStatusChanged(bool))); - connect(m_masterKeyCombo, SIGNAL(activated(int)), this, SLOT(slotIdChanged())); - connect(kcfg_GpgRecipientList, SIGNAL(changed()), this, SLOT(slotIdChanged())); - connect(kcfg_GpgRecipientList, SIGNAL(added(QString)), this, SLOT(slotKeyListChanged())); - connect(kcfg_GpgRecipientList, SIGNAL(removed(QString)), this, SLOT(slotKeyListChanged())); + connect(d->ui->kcfg_WriteDataEncrypted, &QAbstractButton::toggled, this, &KSettingsGpg::slotStatusChanged); + connect(d->ui->m_masterKeyCombo, static_cast(&QComboBox::activated), this, static_cast(&KSettingsGpg::slotIdChanged)); + connect(d->ui->kcfg_GpgRecipientList, &KEditListWidget::changed, this, static_cast(&KSettingsGpg::slotIdChanged)); + connect(d->ui->kcfg_GpgRecipientList, &KEditListWidget::added, this, &KSettingsGpg::slotKeyListChanged); + connect(d->ui->kcfg_GpgRecipientList, &KEditListWidget::removed, this, &KSettingsGpg::slotKeyListChanged); // Initial state setup - slotStatusChanged(kcfg_WriteDataEncrypted->isChecked()); + slotStatusChanged(d->ui->kcfg_WriteDataEncrypted->isChecked()); } KSettingsGpg::~KSettingsGpg() { + Q_D(KSettingsGpg); + delete d; } void KSettingsGpg::slotKeyListChanged() { - m_needCheckList = true; + Q_D(KSettingsGpg); + d->m_needCheckList = true; slotIdChanged(); } void KSettingsGpg::slotIdChanged() { + Q_D(KSettingsGpg); // this looks a bit awkward. Here's why: KGPGFile::keyAvailable() starts // an external task and processes UI events while it waits for the external // process to finish. Thus, the first time we get here, the external process // is started and the user may press a second key which calls this routine // again. // // The second invocation is counted, but the check is not started until the // first one finishes. Once the external process finishes, we check if we // were called in the meantime and restart the check. - if (++m_checkCount == 1) { + if (++d->m_checkCount == 1) { while (1) { // first we check the current edit field if filled bool keysOk = true; - if (!kcfg_GpgRecipientList->currentText().isEmpty()) { - keysOk = KGPGFile::keyAvailable(kcfg_GpgRecipientList->currentText()); + if (!d->ui->kcfg_GpgRecipientList->currentText().isEmpty()) { + keysOk = KGPGFile::keyAvailable(d->ui->kcfg_GpgRecipientList->currentText()); } // if it is available, then scan the current list if we need to if (keysOk) { - if (m_needCheckList) { - QStringList keys = kcfg_GpgRecipientList->items(); + if (d->m_needCheckList) { + QStringList keys = d->ui->kcfg_GpgRecipientList->items(); QStringList::const_iterator it_s; for (it_s = keys.constBegin(); keysOk && it_s != keys.constEnd(); ++it_s) { if (!KGPGFile::keyAvailable(*it_s)) keysOk = false; } - m_listOk = keysOk; - m_needCheckList = false; + d->m_listOk = keysOk; + d->m_needCheckList = false; } else { - keysOk = m_listOk; + keysOk = d->m_listOk; } } // did we receive some more requests to check? - if (m_checkCount > 1) { - m_checkCount = 1; + if (d->m_checkCount > 1) { + d->m_checkCount = 1; continue; } // if we have a master key, we store it in the hidden widget - if (m_masterKeyCombo->currentIndex() != 0) { + if (d->ui->m_masterKeyCombo->currentIndex() != 0) { QRegExp keyExp(".* \\((.*)\\)"); - if (keyExp.indexIn(m_masterKeyCombo->currentText()) != -1) { - kcfg_GpgRecipient->setText(keyExp.cap(1)); + if (keyExp.indexIn(d->ui->m_masterKeyCombo->currentText()) != -1) { + d->ui->kcfg_GpgRecipient->setText(keyExp.cap(1)); } } - m_userKeysFound->setState(static_cast(keysOk && (kcfg_GpgRecipientList->items().count() != 0) ? KLed::On : KLed::Off)); + d->ui->m_userKeysFound->setState(static_cast(keysOk && (d->ui->kcfg_GpgRecipientList->items().count() != 0) ? KLed::On : KLed::Off)); break; } - --m_checkCount; + --d->m_checkCount; } } +void KSettingsGpg::slotIdChanged(int) +{ + slotIdChanged(); +} + void KSettingsGpg::showEvent(QShowEvent * event) { + Q_D(KSettingsGpg); QString masterKey; - if (m_masterKeyCombo->currentIndex() != 0) { + if (d->ui->m_masterKeyCombo->currentIndex() != 0) { QRegExp keyExp(".* \\((.*)\\)"); - if (keyExp.indexIn(m_masterKeyCombo->currentText()) != -1) { + if (keyExp.indexIn(d->ui->m_masterKeyCombo->currentText()) != -1) { masterKey = keyExp.cap(1); } } else - masterKey = kcfg_GpgRecipient->text(); + masterKey = d->ui->kcfg_GpgRecipient->text(); // fill the secret key combobox with a fresh list - m_masterKeyCombo->clear(); + d->ui->m_masterKeyCombo->clear(); QStringList keyList; KGPGFile::secretKeyList(keyList); for (QStringList::iterator it = keyList.begin(); it != keyList.end(); ++it) { QStringList fields = (*it).split(':', QString::SkipEmptyParts); if (fields[0] != RECOVER_KEY_ID_FULL) { // replace parenthesis in name field with brackets QString name = fields[1]; name.replace('(', "["); name.replace(')', "]"); name = QString("%1 (0x%2)").arg(name).arg(fields[0]); - m_masterKeyCombo->addItem(name); + d->ui->m_masterKeyCombo->addItem(name); if (name.contains(masterKey)) - m_masterKeyCombo->setCurrentItem(name); + d->ui->m_masterKeyCombo->setCurrentItem(name); } } // if we don't have at least one secret key, we turn off encryption if (keyList.isEmpty()) { setEnabled(false); - kcfg_WriteDataEncrypted->setChecked(false); + d->ui->kcfg_WriteDataEncrypted->setChecked(false); } - slotStatusChanged(kcfg_WriteDataEncrypted->isChecked()); - KSettingsGpgDecl::showEvent(event); + slotStatusChanged(d->ui->kcfg_WriteDataEncrypted->isChecked()); + QWidget::showEvent(event); } void KSettingsGpg::slotStatusChanged(bool state) { + Q_D(KSettingsGpg); static bool oncePerSession = true; if (state && !KGPGFile::GPGAvailable()) state = false; if ((state == true) && (oncePerSession == true) && isVisible()) { KMessageBox::information(this, QString("%1").arg(i18n("

You have turned on the GPG encryption support. This means, that new files will be stored encrypted.

Existing files will not be encrypted automatically. To achieve encryption of existing files, please use the File/Save as... feature and store the file under a different name.
Once confident with the result, feel free to delete the old file and rename the encrypted one to the old name.

")), i18n("GPG encryption activated"), "GpgEncryptionActivated"); oncePerSession = false; } - m_idGroup->setEnabled(state); - kcfg_EncryptRecover->setEnabled(state); - m_masterKeyCombo->setEnabled(state); - kcfg_GpgRecipientList->setEnabled(state); + d->ui->m_recoverKeyFound->setEnabled(state); + d->ui->kcfg_EncryptRecover->setEnabled(state); + d->ui->m_masterKeyCombo->setEnabled(state); + d->ui->kcfg_GpgRecipientList->setEnabled(state); if (state) { - m_recoverKeyFound->setState((KLed::State)(KGPGFile::keyAvailable(RECOVER_KEY_ID) ? KLed::On : KLed::Off)); - kcfg_EncryptRecover->setEnabled(m_recoverKeyFound->state() == KLed::On); + d->ui->m_recoverKeyFound->setState((KLed::State)(KGPGFile::keyAvailable(RECOVER_KEY_ID) ? KLed::On : KLed::Off)); + d->ui->kcfg_EncryptRecover->setEnabled(d->ui->m_recoverKeyFound->state() == KLed::On); slotIdChanged(); } else { - m_recoverKeyFound->setState(KLed::Off); - m_userKeysFound->setState(KLed::Off); + d->ui->m_recoverKeyFound->setState(KLed::Off); + d->ui->m_userKeysFound->setState(KLed::Off); } } diff --git a/kmymoney/dialogs/settings/ksettingsgpg.h b/kmymoney/dialogs/settings/ksettingsgpg.h index 9d5e01f0e..864b99c7f 100644 --- a/kmymoney/dialogs/settings/ksettingsgpg.h +++ b/kmymoney/dialogs/settings/ksettingsgpg.h @@ -1,64 +1,58 @@ /*************************************************************************** ksettingsgpg.h ------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSETTINGSGPG_H #define KSETTINGSGPG_H // ---------------------------------------------------------------------------- // QT Includes -class QShowEvent; +#include // ---------------------------------------------------------------------------- // KDE Includes - // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ksettingsgpgdecl.h" - -class KSettingsGpgDecl : public QWidget, public Ui::KSettingsGpgDecl -{ -public: - KSettingsGpgDecl(QWidget *parent) : QWidget(parent) { - setupUi(this); - } -}; +class QShowEvent; -class KSettingsGpg : public KSettingsGpgDecl +class KSettingsGpgPrivate; +class KSettingsGpg : public QWidget { Q_OBJECT + Q_DISABLE_COPY(KSettingsGpg) public: - KSettingsGpg(QWidget* parent = 0); + explicit KSettingsGpg(QWidget* parent = nullptr); ~KSettingsGpg(); public slots: - void showEvent(QShowEvent * event); + void showEvent(QShowEvent * event) override; protected slots: void slotStatusChanged(bool state); void slotIdChanged(); + void slotIdChanged(int idx); void slotKeyListChanged(); private: - int m_checkCount; - bool m_needCheckList; - bool m_listOk; + KSettingsGpgPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KSettingsGpg) }; #endif diff --git a/kmymoney/dialogs/settings/ksettingsgpgdecl.ui b/kmymoney/dialogs/settings/ksettingsgpg.ui similarity index 98% rename from kmymoney/dialogs/settings/ksettingsgpgdecl.ui rename to kmymoney/dialogs/settings/ksettingsgpg.ui index 87b9dac83..96c13444d 100644 --- a/kmymoney/dialogs/settings/ksettingsgpgdecl.ui +++ b/kmymoney/dialogs/settings/ksettingsgpg.ui @@ -1,231 +1,231 @@ - KSettingsGpgDecl - + KSettingsGpg + 0 0 409 486 GPG encryption settings This page allows you to set the parameters for encrypted file storage of your <b>KMyMoney</b> data based on <b>GPG</b>.<p> Access to the settings is disabled if <b>GPG</b> could not be detected on your system. In this case, please make sure that <b>GPG</b> is working properly for the current user.<p> The <i>additional recovery encryption</i> is only accessible, if the necessary key for <b>kmymoney-recover@users.sourceforge.net</b> with id 0x8AFDDC8E is found in your keyring. Use GPG encryption GPG encryption Your key false 1 0 This combo box lists all the secret keys you have in your keyring. Select the one you want to use for encryption when saving to a file. Additional keys Enter the id of the key you want to use for data encryption. This can either be an e-mail address or the hexadecimal key id. In case of the key id do not forget the leading 0x. KEditListWidget::Add|KEditListWidget::Remove Additional keys This symbol denotes, if the key for the given user id has been found in your keyring. It is green when found, dark otherwise. KLed::Circular KLed::Sunken Keys for all of the above user ids found false Qt::Horizontal QSizePolicy::Expanding 50 20 This symbol denotes, if the KMyMoney recovery key has been found in your keyring. It is green when found, dark otherwise. KLed::Circular KLed::Sunken Recover Key available in keyring false Qt::Horizontal QSizePolicy::Expanding 16 20 You can specify to encrypt the data also with the KMyMoney recover key. Only the core KMyMoney developers are in posession of the respective private key required to read back such encrypted data.<p> This mechanism is provided for the case that you have lost your key and cannot access your data anymore. With this option activated, the KMyMoney developers can decrypt the data and supply you with it in a readable form. Please be prepared, that you have to answer a few detailed questions about the contents of your data before we will send it out. Also encrypt with KMyMoney's recover key Qt::Vertical QSizePolicy::Expanding 21 30 KLineEdit QLineEdit
klineedit.h
KEditListWidget QWidget
keditlistwidget.h
KComboBox QComboBox
kcombobox.h
KLed QWidget
kled.h
diff --git a/kmymoney/dialogs/settings/ksettingshome.cpp b/kmymoney/dialogs/settings/ksettingshome.cpp index d8bf48685..033242d0f 100644 --- a/kmymoney/dialogs/settings/ksettingshome.cpp +++ b/kmymoney/dialogs/settings/ksettingshome.cpp @@ -1,176 +1,199 @@ /*************************************************************************** ksettingshome.cpp -------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "ksettingshome.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include -#include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_ksettingshome.h" + #include "kmymoney/kmymoneyglobalsettings.h" #include "kmymoney/kmymoneyutils.h" #include "icons/icons.h" using namespace Icons; -KSettingsHome::KSettingsHome(QWidget* parent) : - KSettingsHomeDecl(parent), +class KSettingsHomePrivate +{ + Q_DISABLE_COPY(KSettingsHomePrivate) + +public: + KSettingsHomePrivate() : + ui(new Ui::KSettingsHome), m_noNeedToUpdateList(false) + { + } + + ~KSettingsHomePrivate() + { + delete ui; + } + + Ui::KSettingsHome *ui; + bool m_noNeedToUpdateList; +}; + +KSettingsHome::KSettingsHome(QWidget* parent) : + QWidget(parent), + d_ptr(new KSettingsHomePrivate) { - m_homePageList->setSortingEnabled(false); - - KGuiItem upButtonItem(i18nc("Move item up", "&Up"), - QIcon::fromTheme(g_Icons[Icon::ArrowUp]), - i18n("Move selected item up"), - i18n("Use this to move the selected item up by one position in the list.")); - KGuiItem downButtonItem(i18n("&Down"), - QIcon::fromTheme(g_Icons[Icon::ArrowDown]), - i18n("Move selected item down"), - i18n("Use this to move the selected item down by one position in the list.")); - - KGuiItem::assign(m_upButton, upButtonItem); - m_upButton->setEnabled(false); - KGuiItem::assign(m_downButton, downButtonItem); - m_downButton->setEnabled(false); + Q_D(KSettingsHome); + d->ui->setupUi(this); + d->ui->m_homePageList->setSortingEnabled(false); + + d->ui->m_upButton->setIcon(QIcon::fromTheme(g_Icons[Icon::ArrowUp])); + d->ui->m_downButton->setIcon(QIcon::fromTheme(g_Icons[Icon::ArrowDown])); + + d->ui->m_upButton->setEnabled(false); + d->ui->m_downButton->setEnabled(false); // connect this, so that the list gets loaded once the edit field is filled - connect(kcfg_ItemList, SIGNAL(textChanged(QString)), this, SLOT(slotLoadItems())); + connect(d->ui->kcfg_ItemList, &QLineEdit::textChanged, this, &KSettingsHome::slotLoadItems); - connect(m_homePageList, SIGNAL(itemSelectionChanged()), - this, SLOT(slotSelectHomePageItem())); - connect(m_homePageList, SIGNAL(clicked(QModelIndex)), this, SLOT(slotUpdateItemList())); + connect(d->ui->m_homePageList, &QListWidget::itemSelectionChanged, + this, &KSettingsHome::slotSelectHomePageItem); + connect(d->ui->m_homePageList, &QAbstractItemView::clicked, this, &KSettingsHome::slotUpdateItemList); - connect(m_upButton, SIGNAL(clicked()), this, SLOT(slotMoveUp())); - connect(m_downButton, SIGNAL(clicked()), this, SLOT(slotMoveDown())); + connect(d->ui->m_upButton, &QAbstractButton::clicked, this, &KSettingsHome::slotMoveUp); + connect(d->ui->m_downButton, &QAbstractButton::clicked, this, &KSettingsHome::slotMoveDown); // Don't show it to the user, we only need it to load and save the settings - kcfg_ItemList->hide(); + d->ui->kcfg_ItemList->hide(); } KSettingsHome::~KSettingsHome() { + Q_D(KSettingsHome); + delete d; } void KSettingsHome::slotLoadItems() { - if (m_noNeedToUpdateList) + Q_D(KSettingsHome); + if (d->m_noNeedToUpdateList) return; QStringList list = KMyMoneyGlobalSettings::itemList(); QStringList::ConstIterator it; - m_homePageList->clear(); + d->ui->m_homePageList->clear(); QListWidgetItem *sel = 0; for (it = list.constBegin(); it != list.constEnd(); ++it) { int idx = (*it).toInt(); // skip over unknown item entries if (idx == 0) continue; bool enabled = idx > 0; if (!enabled) idx = -idx; - QListWidgetItem* item = new QListWidgetItem(m_homePageList); + QListWidgetItem* item = new QListWidgetItem(d->ui->m_homePageList); item->setText(KMyMoneyUtils::homePageItemToString(idx)); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // qDebug("Adding %s", item->text(0).toLatin1()); if (enabled) { item->setCheckState(Qt::Checked); } else { item->setCheckState(Qt::Unchecked); } if (sel == 0) sel = item; } if (sel) { - m_homePageList->setCurrentItem(sel); + d->ui->m_homePageList->setCurrentItem(sel); slotSelectHomePageItem(); } } void KSettingsHome::slotUpdateItemList() { + Q_D(KSettingsHome); QString list; QListWidgetItem *it; - for (it = m_homePageList->item(0); it;) { + for (it = d->ui->m_homePageList->item(0); it;) { int item = KMyMoneyUtils::stringToHomePageItem(it->text()); if (it->checkState() == Qt::Unchecked) item = -item; list += QString::number(item); - if (m_homePageList->count() > (m_homePageList->row(it) + 1)) { - it = m_homePageList->item(m_homePageList->row(it) + 1); + if (d->ui->m_homePageList->count() > (d->ui->m_homePageList->row(it) + 1)) { + it = d->ui->m_homePageList->item(d->ui->m_homePageList->row(it) + 1); if (it) { list += ','; } } else { break; } } // don't update the list - m_noNeedToUpdateList = true; - kcfg_ItemList->setText(list); - m_noNeedToUpdateList = false; + d->m_noNeedToUpdateList = true; + d->ui->kcfg_ItemList->setText(list); + d->m_noNeedToUpdateList = false; } void KSettingsHome::slotSelectHomePageItem() { - QListWidgetItem* item = m_homePageList->currentItem(); - m_upButton->setEnabled(m_homePageList->item(0) != item); - m_downButton->setEnabled(m_homePageList->count() > (m_homePageList->row(item) + 1)); + Q_D(KSettingsHome); + auto item = d->ui->m_homePageList->currentItem(); + d->ui->m_upButton->setEnabled(d->ui->m_homePageList->item(0) != item); + d->ui->m_downButton->setEnabled(d->ui->m_homePageList->count() > (d->ui->m_homePageList->row(item) + 1)); } void KSettingsHome::slotMoveUp() { - QListWidgetItem *item = m_homePageList->currentItem(); - QListWidgetItem *prev = m_homePageList->item(m_homePageList->row(item) - 1); - int prevRow = m_homePageList->row(prev); + Q_D(KSettingsHome); + auto item = d->ui->m_homePageList->currentItem(); + auto prev = d->ui->m_homePageList->item(d->ui->m_homePageList->row(item) - 1); + int prevRow = d->ui->m_homePageList->row(prev); if (prev) { - m_homePageList->takeItem(m_homePageList->row(item)); - m_homePageList->insertItem(prevRow, item); - m_homePageList->setCurrentRow(m_homePageList->row(item)); + d->ui->m_homePageList->takeItem(d->ui->m_homePageList->row(item)); + d->ui->m_homePageList->insertItem(prevRow, item); + d->ui->m_homePageList->setCurrentRow(d->ui->m_homePageList->row(item)); slotSelectHomePageItem(); slotUpdateItemList(); } } void KSettingsHome::slotMoveDown() { - QListWidgetItem *item = m_homePageList->currentItem(); - QListWidgetItem *next = m_homePageList->item(m_homePageList->row(item) + 1); - int nextRow = m_homePageList->row(next); + Q_D(KSettingsHome); + auto item = d->ui->m_homePageList->currentItem(); + auto next = d->ui->m_homePageList->item(d->ui->m_homePageList->row(item) + 1); + int nextRow = d->ui->m_homePageList->row(next); if (next) { - m_homePageList->takeItem(m_homePageList->row(item)); - m_homePageList->insertItem(nextRow, item); - m_homePageList->setCurrentRow(m_homePageList->row(item)); + d->ui->m_homePageList->takeItem(d->ui->m_homePageList->row(item)); + d->ui->m_homePageList->insertItem(nextRow, item); + d->ui->m_homePageList->setCurrentRow(d->ui->m_homePageList->row(item)); slotSelectHomePageItem(); slotUpdateItemList(); } } diff --git a/kmymoney/dialogs/settings/ksettingshome.h b/kmymoney/dialogs/settings/ksettingshome.h index edf4ba7bb..5893b7575 100644 --- a/kmymoney/dialogs/settings/ksettingshome.h +++ b/kmymoney/dialogs/settings/ksettingshome.h @@ -1,59 +1,54 @@ /*************************************************************************** ksettingshome.h ------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSETTINGSHOME_H #define KSETTINGSHOME_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ksettingshomedecl.h" - -class KSettingsHomeDecl : public QWidget, public Ui::KSettingsHomeDecl -{ -public: - KSettingsHomeDecl(QWidget *parent) : QWidget(parent) { - setupUi(this); - } -}; - - -class KSettingsHome : public KSettingsHomeDecl +class KSettingsHomePrivate; +class KSettingsHome : public QWidget { Q_OBJECT + Q_DISABLE_COPY(KSettingsHome) public: - KSettingsHome(QWidget* parent = 0); + explicit KSettingsHome(QWidget* parent = nullptr); ~KSettingsHome(); protected slots: void slotLoadItems(); void slotUpdateItemList(); void slotSelectHomePageItem(); void slotMoveUp(); void slotMoveDown(); private: - bool m_noNeedToUpdateList; + KSettingsHomePrivate * const d_ptr; + Q_DECLARE_PRIVATE(KSettingsHome) }; #endif diff --git a/kmymoney/dialogs/settings/ksettingshomedecl.ui b/kmymoney/dialogs/settings/ksettingshome.ui similarity index 92% rename from kmymoney/dialogs/settings/ksettingshomedecl.ui rename to kmymoney/dialogs/settings/ksettingshome.ui index b0432984f..b5b3bf2e5 100644 --- a/kmymoney/dialogs/settings/ksettingshomedecl.ui +++ b/kmymoney/dialogs/settings/ksettingshome.ui @@ -1,231 +1,243 @@ - KSettingsHomeDecl - + KSettingsHome + 0 0 659 520 Homepage Settings Qt::Vertical QSizePolicy::Fixed 20 20 + + Move selected item up + + + Use this to move the selected item up by one position in the list. + Up + + Move selected item down + + + Use this to move the selected item down by one position in the list. + Down Qt::Vertical QSizePolicy::Expanding 21 70 Qt::Horizontal QSizePolicy::Expanding 80 21 0 0 Selected entries are shown on the home page of the application.<p> Use the buttons and checkboxes to customize the layout of the home page. Qt::AlignTop true Homepage/Summary page scaling Zoom factor: false Remember zoom factor when leaving the program if manually changed with mouse-wheel 0.250000000000000 5.000000000000000 0.050000000000000 1.000000000000000 Qt::Horizontal QSizePolicy::Expanding 40 20 Account information display Show Account Limit Information Show balance-status of mapped online accounts Show number of not marked transactions per account [!M] Show number of cleared transactions per account [C] Show number of not reconciled (not marked + cleared) transactions per account [!R] KLineEdit QLineEdit
klineedit.h
diff --git a/kmymoney/dialogs/settings/ksettingsicons.cpp b/kmymoney/dialogs/settings/ksettingsicons.cpp index f3629cbaf..e89e72f3f 100644 --- a/kmymoney/dialogs/settings/ksettingsicons.cpp +++ b/kmymoney/dialogs/settings/ksettingsicons.cpp @@ -1,90 +1,120 @@ /*************************************************************************** ksettingsicons.cpp -------------------- copyright : (C) 2017 by Łukasz Wojniłowicz email : lukasz.wojnilowicz@gmail.com ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "ksettingsicons.h" // ---------------------------------------------------------------------------- // QT Includes #include #include -#include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes +#include "ui_ksettingsicons.h" + +class KSettingsIconsPrivate +{ + Q_DISABLE_COPY(KSettingsIconsPrivate) + +public: + KSettingsIconsPrivate() : + ui(new Ui::KSettingsIcons) + { + } + + ~KSettingsIconsPrivate() + { + delete ui; + } + + Ui::KSettingsIcons *ui; + QMap m_themesMap; +}; + KSettingsIcons::KSettingsIcons(QWidget* parent) : - KSettingsIconsDecl(parent) + QWidget(parent), + d_ptr(new KSettingsIconsPrivate) { + Q_D(KSettingsIcons); + d->ui->setupUi(this); // hide the internally used holidayRegion field - kcfg_IconsTheme->hide(); + d->ui->kcfg_IconsTheme->hide(); loadList(); // setup connections so that region gets selected once field is filled - connect(kcfg_IconsTheme, SIGNAL(textChanged(QString)), this, SLOT(slotLoadTheme(QString))); + connect(d->ui->kcfg_IconsTheme, &QLineEdit::textChanged, this, &KSettingsIcons::slotLoadTheme); // setup connections so that changes are forwarded to the field - connect(m_IconsTheme, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSetTheme(int))); + connect(d->ui->m_IconsTheme, + static_cast(&QComboBox::currentIndexChanged), this, &KSettingsIcons::slotSetTheme); +} + +KSettingsIcons::~KSettingsIcons() +{ + Q_D(KSettingsIcons); + delete d; } void KSettingsIcons::loadList() { + Q_D(KSettingsIcons); QStringList themes {QStringLiteral("oxygen"), QStringLiteral("Tango"), QStringLiteral("breeze"), QStringLiteral("breeze-dark")}; QStringList searchPaths = QIcon::themeSearchPaths(); - m_IconsTheme->addItem(QStringLiteral("system")); - m_themesMap.insert(0, QStringLiteral("system")); - for (int i = 0; i < searchPaths.count(); ++i) { + d->ui->m_IconsTheme->addItem(QStringLiteral("system")); + d->m_themesMap.insert(0, QStringLiteral("system")); + for (auto i = 0; i < searchPaths.count(); ++i) { for (int j = 0; j < themes.count(); ++j) { QDir themeDir = QDir(searchPaths.at(i)).filePath(themes.at(j)); if (themeDir.exists(QStringLiteral("index.theme"))) { - m_IconsTheme->addItem(themes.at(j)); - m_themesMap.insert(m_themesMap.count(), themes.at(j)); + d->ui->m_IconsTheme->addItem(themes.at(j)); + d->m_themesMap.insert(d->m_themesMap.count(), themes.at(j)); } } } } void KSettingsIcons::slotSetTheme(const int &theme) { - kcfg_IconsTheme->setText(m_themesMap.value(theme)); + Q_D(KSettingsIcons); + d->ui->kcfg_IconsTheme->setText(d->m_themesMap.value(theme)); } void KSettingsIcons::slotLoadTheme(const QString &theme) { + Q_D(KSettingsIcons); // only need this once - disconnect(kcfg_IconsTheme, SIGNAL(textChanged(QString)), this, SLOT(slotLoadTheme(QString))); - int i = 0; + disconnect(d->ui->kcfg_IconsTheme, &QLineEdit::textChanged, this, &KSettingsIcons::slotLoadTheme); + auto i = 0; if (!theme.isEmpty()) - i = m_IconsTheme->findText(theme); - if ((i > -1) && (i != m_IconsTheme->currentIndex())) { - m_IconsTheme->blockSignals(true); - m_IconsTheme->setCurrentIndex(i); - m_IconsTheme->blockSignals(false); + i = d->ui->m_IconsTheme->findText(theme); + if ((i > -1) && (i != d->ui->m_IconsTheme->currentIndex())) { + d->ui->m_IconsTheme->blockSignals(true); + d->ui->m_IconsTheme->setCurrentIndex(i); + d->ui->m_IconsTheme->blockSignals(false); } } void KSettingsIcons::slotResetTheme() { - slotLoadTheme(kcfg_IconsTheme->text()); -} - -KSettingsIcons::~KSettingsIcons() -{ + Q_D(KSettingsIcons); + slotLoadTheme(d->ui->kcfg_IconsTheme->text()); } diff --git a/kmymoney/dialogs/settings/ksettingsicons.h b/kmymoney/dialogs/settings/ksettingsicons.h index 47537d45a..2c816a837 100644 --- a/kmymoney/dialogs/settings/ksettingsicons.h +++ b/kmymoney/dialogs/settings/ksettingsicons.h @@ -1,60 +1,55 @@ /*************************************************************************** ksettingsicons.h ------------------- copyright : (C) 2017 by Łukasz Wojniłowicz email : lukasz.wojnilowicz@gmail.com ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #ifndef KSETTINGSICONS_H #define KSETTINGSICONS_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ksettingsiconsdecl.h" - -class KSettingsIconsDecl : public QWidget, public Ui::KSettingsIconsDecl -{ -public: - KSettingsIconsDecl(QWidget *parent) : QWidget(parent) { - setupUi(this); - } -}; - -class KSettingsIcons : public KSettingsIconsDecl +class KSettingsIconsPrivate; +class KSettingsIcons : public QWidget { Q_OBJECT + Q_DISABLE_COPY(KSettingsIcons) public: - KSettingsIcons(QWidget* parent = 0); + explicit KSettingsIcons(QWidget* parent = nullptr); ~KSettingsIcons(); public slots: void slotResetTheme(); protected slots: void slotLoadTheme(const QString &theme); void slotSetTheme(const int &theme); protected: void loadList(); private: - QMap m_themesMap; + KSettingsIconsPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KSettingsIcons) }; #endif diff --git a/kmymoney/dialogs/settings/ksettingsiconsdecl.ui b/kmymoney/dialogs/settings/ksettingsicons.ui similarity index 97% rename from kmymoney/dialogs/settings/ksettingsiconsdecl.ui rename to kmymoney/dialogs/settings/ksettingsicons.ui index b3b8ea4a7..1e2783584 100644 --- a/kmymoney/dialogs/settings/ksettingsiconsdecl.ui +++ b/kmymoney/dialogs/settings/ksettingsicons.ui @@ -1,103 +1,103 @@ - KSettingsIconsDecl - + KSettingsIcons + 0 0 398 222 Font settings Individual icon settings 0 0 Qt::Horizontal QSizePolicy::Expanding 110 20 Icon theme false 0 0 <html><head/><body><p align="center">Tip: Install Oxygen, Tango or Breeze icon theme to get wider selection.</p></body></html> true Qt::Vertical QSizePolicy::Expanding 20 30 diff --git a/kmymoney/dialogs/settings/ksettingskmymoney.cpp b/kmymoney/dialogs/settings/ksettingskmymoney.cpp index 20b615ea8..ef56e3acc 100644 --- a/kmymoney/dialogs/settings/ksettingskmymoney.cpp +++ b/kmymoney/dialogs/settings/ksettingskmymoney.cpp @@ -1,79 +1,83 @@ /* * This file is part of KMyMoney, A Personal Finance Manager by KDE * Copyright (C) 2016 Christian Dávid + * (C) 2017 by Ł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 "ksettingskmymoney.h" +#include + #include +#include #include "ksettingsgeneral.h" #include "ksettingsregister.h" #include "ksettingsgpg.h" #include "ksettingscolors.h" #include "ksettingsfonts.h" #include "ksettingsicons.h" #include "ksettingsschedules.h" #include "ksettingsonlinequotes.h" #include "ksettingshome.h" #include "ksettingsforecast.h" #include "ksettingsreports.h" #include "pluginloader.h" #include "icons/icons.h" using namespace Icons; KSettingsKMyMoney::KSettingsKMyMoney(QWidget *parent, const QString &name, KCoreConfigSkeleton *config) : KConfigDialog(parent, name, config) { // create the pages ... - KSettingsGeneral* generalPage = new KSettingsGeneral(); - KSettingsRegister* registerPage = new KSettingsRegister(); - KSettingsHome* homePage = new KSettingsHome(); - KSettingsSchedules* schedulesPage = new KSettingsSchedules(); - KSettingsGpg* encryptionPage = new KSettingsGpg(); - KSettingsColors* colorsPage = new KSettingsColors(); - KSettingsFonts* fontsPage = new KSettingsFonts(); - KSettingsIcons* iconsPage = new KSettingsIcons(); - KSettingsOnlineQuotes* onlineQuotesPage = new KSettingsOnlineQuotes(); - KSettingsForecast* forecastPage = new KSettingsForecast(); - KPluginSelector* pluginsPage = KMyMoneyPlugin::PluginLoader::instance()->pluginSelectorWidget(); - KSettingsReports* reportsPage = new KSettingsReports(); + const auto generalPage = new KSettingsGeneral(); + const auto registerPage = new KSettingsRegister(); + const auto homePage = new KSettingsHome(); + const auto schedulesPage = new KSettingsSchedules(); + const auto encryptionPage = new KSettingsGpg(); + const auto colorsPage = new KSettingsColors(); + const auto fontsPage = new KSettingsFonts(); + const auto iconsPage = new KSettingsIcons(); + const auto onlineQuotesPage = new KSettingsOnlineQuotes(); + const auto forecastPage = new KSettingsForecast(); + const auto pluginsPage = KMyMoneyPlugin::PluginLoader::instance()->pluginSelectorWidget(); + const auto reportsPage = new KSettingsReports(); addPage(generalPage, i18nc("General settings", "General"), g_Icons[Icon::SystemRun]); addPage(homePage, i18n("Home"), g_Icons[Icon::ViewHome]); addPage(registerPage, i18nc("Ledger view settings", "Ledger"), g_Icons[Icon::ViewFinancialList]); addPage(schedulesPage, i18n("Scheduled transactions"), g_Icons[Icon::ViewSchedules]); addPage(onlineQuotesPage, i18n("Online Quotes"), g_Icons[Icon::PreferencesNetwork]); addPage(reportsPage, i18nc("Report settings", "Reports"), g_Icons[Icon::ViewReports]); addPage(forecastPage, i18nc("Forecast settings", "Forecast"), g_Icons[Icon::ViewForecast]); addPage(encryptionPage, i18n("Encryption"), g_Icons[Icon::Kgpg]); addPage(colorsPage, i18n("Colors"), g_Icons[Icon::PreferencesColor]); addPage(fontsPage, i18n("Fonts"), g_Icons[Icon::PreferencesFont]); addPage(iconsPage, i18n("Icons"), g_Icons[Icon::PreferencesIcon]); addPage(pluginsPage, i18n("Plugins"), g_Icons[Icon::NetworkDisconect]); setHelp("details.settings", "kmymoney"); - QAbstractButton* defaultButton = button(QDialogButtonBox::RestoreDefaults); + auto defaultButton = button(QDialogButtonBox::RestoreDefaults); connect(this, &KConfigDialog::rejected, schedulesPage, &KSettingsSchedules::slotResetRegion); connect(this, &KConfigDialog::rejected, iconsPage, &KSettingsIcons::slotResetTheme); connect(this, &KConfigDialog::settingsChanged, generalPage, &KSettingsGeneral::slotUpdateEquitiesVisibility); connect(this, &KConfigDialog::accepted, pluginsPage, &KPluginSelector::save); - connect(defaultButton, &QAbstractButton::clicked, pluginsPage, &KPluginSelector::defaults); + connect(defaultButton, &QPushButton::clicked, pluginsPage, &KPluginSelector::defaults); } diff --git a/kmymoney/dialogs/settings/ksettingskmymoney.h b/kmymoney/dialogs/settings/ksettingskmymoney.h index ae5806484..365cc7e7d 100644 --- a/kmymoney/dialogs/settings/ksettingskmymoney.h +++ b/kmymoney/dialogs/settings/ksettingskmymoney.h @@ -1,34 +1,35 @@ /* * This file is part of KMyMoney, A Personal Finance Manager by KDE * Copyright (C) 2016 Christian Dávid + * (C) 2017 by Ł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 KSETTINGSKMYMONEY_H #define KSETTINGSKMYMONEY_H #include /** * @brief The general settings dialog */ class KSettingsKMyMoney : public KConfigDialog { public: - KSettingsKMyMoney(QWidget *parent, const QString &name, KCoreConfigSkeleton *config); + explicit KSettingsKMyMoney(QWidget *parent, const QString &name, KCoreConfigSkeleton *config); }; #endif /* KSETTINGSKMYMONEY_H */ diff --git a/kmymoney/dialogs/settings/ksettingsonlinequotes.cpp b/kmymoney/dialogs/settings/ksettingsonlinequotes.cpp index 1ea61c595..89c4c73c6 100644 --- a/kmymoney/dialogs/settings/ksettingsonlinequotes.cpp +++ b/kmymoney/dialogs/settings/ksettingsonlinequotes.cpp @@ -1,334 +1,376 @@ /*************************************************************************** ksettingsonlinequotes.cpp ------------------- begin : Thu Dec 30 2004 copyright : (C) 2004 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "ksettingsonlinequotes.h" // ---------------------------------------------------------------------------- // QT Includes #include #include // ---------------------------------------------------------------------------- // KDE Includes #include -#include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_ksettingsonlinequotes.h" + #include "kmymoney/converter/webpricequote.h" #include "mymoneyfile.h" #include "mymoneysecurity.h" #include "icons/icons.h" using namespace Icons; -KSettingsOnlineQuotes::KSettingsOnlineQuotes(QWidget *parent) - : KSettingsOnlineQuotesDecl(parent), - m_quoteInEditing(false) +class KSettingsOnlineQuotesPrivate +{ + Q_DISABLE_COPY(KSettingsOnlineQuotesPrivate) + +public: + KSettingsOnlineQuotesPrivate() : + ui(new Ui::KSettingsOnlineQuotes) + { + } + + ~KSettingsOnlineQuotesPrivate() + { + delete ui; + } + + Ui::KSettingsOnlineQuotes *ui; + QList m_resetList; + WebPriceQuoteSource m_currentItem; + bool m_quoteInEditing; +}; + +KSettingsOnlineQuotes::KSettingsOnlineQuotes(QWidget *parent) : + QWidget(parent), + d_ptr(new KSettingsOnlineQuotesPrivate) { + Q_D(KSettingsOnlineQuotes); + d->ui->setupUi(this); QStringList groups = WebPriceQuote::quoteSources(); loadList(true /*updateResetList*/); - m_updateButton->setEnabled(false); - - KGuiItem updateButtenItem(i18nc("Accepts the entered data and stores it", "&Update"), - QIcon::fromTheme(g_Icons[Icon::DialogOK]), - i18n("Accepts the entered data and stores it"), - i18n("Use this to accept the modified data.")); - KGuiItem::assign(m_updateButton, updateButtenItem); - - KGuiItem deleteButtenItem(i18n("&Delete"), - QIcon::fromTheme(g_Icons[Icon::EditDelete]), - i18n("Delete the selected source entry"), - i18n("Use this to delete the selected online source entry")); - KGuiItem::assign(m_deleteButton, deleteButtenItem); - - KGuiItem newButtenItem(i18nc("Create a new source entry for online quotes", "&New..."), - QIcon::fromTheme(g_Icons[Icon::DocumentNew]), - i18n("Create a new source entry for online quotes"), - i18n("Use this to create a new entry for online quotes")); - KGuiItem::assign(m_newButton, newButtenItem); - - m_editIdentifyBy->addItem(i18n("Symbol"), WebPriceQuoteSource::identifyBy::Symbol); - m_editIdentifyBy->addItem(i18n("Identification number"), WebPriceQuoteSource::identifyBy::IdentificationNumber); - m_editIdentifyBy->addItem(i18n("Name"), WebPriceQuoteSource::identifyBy::Name); - - connect(m_dumpCSVProfile, SIGNAL(clicked()), this, SLOT(slotDumpCSVProfile())); - connect(m_updateButton, SIGNAL(clicked()), this, SLOT(slotUpdateEntry())); - connect(m_newButton, SIGNAL(clicked()), this, SLOT(slotNewEntry())); - connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(slotDeleteEntry())); - - connect(m_quoteSourceList, SIGNAL(itemSelectionChanged()), this, SLOT(slotLoadWidgets())); - connect(m_quoteSourceList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(slotEntryRenamed(QListWidgetItem*))); - connect(m_quoteSourceList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(slotStartRename(QListWidgetItem*))); - - connect(m_editURL, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged())); - connect(m_editCSVURL, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged())); - connect(m_editIdentifier, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged())); - connect(m_editIdentifyBy, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotEntryChanged())); - connect(m_editDate, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged())); - connect(m_editDateFormat, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged())); - connect(m_editPrice, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged())); - connect(m_skipStripping, SIGNAL(toggled(bool)), this, SLOT(slotEntryChanged())); + d->ui->m_updateButton->setEnabled(false); + + d->ui->m_updateButton->setIcon(QIcon::fromTheme(g_Icons[Icon::DialogOK])); + d->ui->m_deleteButton->setIcon(QIcon::fromTheme(g_Icons[Icon::EditDelete])); + d->ui->m_newButton->setIcon(QIcon::fromTheme(g_Icons[Icon::DocumentNew])); + + d->ui->m_editIdentifyBy->addItem(i18n("Symbol"), WebPriceQuoteSource::identifyBy::Symbol); + d->ui->m_editIdentifyBy->addItem(i18n("Identification number"), WebPriceQuoteSource::identifyBy::IdentificationNumber); + d->ui->m_editIdentifyBy->addItem(i18n("Name"), WebPriceQuoteSource::identifyBy::Name); + + connect(d->ui->m_dumpCSVProfile, &QAbstractButton::clicked, this, &KSettingsOnlineQuotes::slotDumpCSVProfile); + connect(d->ui->m_updateButton, &QAbstractButton::clicked, this, &KSettingsOnlineQuotes::slotUpdateEntry); + connect(d->ui->m_newButton, &QAbstractButton::clicked, this, &KSettingsOnlineQuotes::slotNewEntry); + connect(d->ui->m_deleteButton, &QAbstractButton::clicked, this, &KSettingsOnlineQuotes::slotDeleteEntry); + + connect(d->ui->m_quoteSourceList, &QListWidget::itemSelectionChanged, this, &KSettingsOnlineQuotes::slotLoadWidgets); + connect(d->ui->m_quoteSourceList, &QListWidget::itemChanged, this, &KSettingsOnlineQuotes::slotEntryRenamed); + connect(d->ui->m_quoteSourceList, &QListWidget::itemDoubleClicked, this, &KSettingsOnlineQuotes::slotStartRename); + + connect(d->ui->m_editURL, &QLineEdit::textChanged, this, static_cast(&KSettingsOnlineQuotes::slotEntryChanged)); + connect(d->ui->m_editCSVURL, &QLineEdit::textChanged, this, static_cast(&KSettingsOnlineQuotes::slotEntryChanged)); + connect(d->ui->m_editIdentifier, &QLineEdit::textChanged, this, static_cast(&KSettingsOnlineQuotes::slotEntryChanged)); + connect(d->ui->m_editIdentifyBy, static_cast(&QComboBox::currentIndexChanged), this, static_cast(&KSettingsOnlineQuotes::slotEntryChanged)); + connect(d->ui->m_editDate, &QLineEdit::textChanged, this, static_cast(&KSettingsOnlineQuotes::slotEntryChanged)); + connect(d->ui->m_editDateFormat, &QLineEdit::textChanged, this, static_cast(&KSettingsOnlineQuotes::slotEntryChanged)); + connect(d->ui->m_editPrice, &QLineEdit::textChanged, this, static_cast(&KSettingsOnlineQuotes::slotEntryChanged)); + connect(d->ui->m_skipStripping, &QAbstractButton::toggled, this, static_cast(&KSettingsOnlineQuotes::slotEntryChanged)); +} + +KSettingsOnlineQuotes::~KSettingsOnlineQuotes() +{ + Q_D(KSettingsOnlineQuotes); + delete d; } void KSettingsOnlineQuotes::loadList(const bool updateResetList) { + Q_D(KSettingsOnlineQuotes); //disconnect the slot while items are being loaded and reconnect at the end - disconnect(m_quoteSourceList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(slotEntryRenamed(QListWidgetItem*))); - m_quoteInEditing = false; + disconnect(d->ui->m_quoteSourceList, &QListWidget::itemChanged, this, &KSettingsOnlineQuotes::slotEntryRenamed); + d->m_quoteInEditing = false; QStringList groups = WebPriceQuote::quoteSources(); if (updateResetList) - m_resetList.clear(); - m_quoteSourceList->clear(); + d->m_resetList.clear(); + d->ui->m_quoteSourceList->clear(); QStringList::Iterator it; for (it = groups.begin(); it != groups.end(); ++it) { QListWidgetItem* item = new QListWidgetItem(*it); item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled); - m_quoteSourceList->addItem(item); + d->ui->m_quoteSourceList->addItem(item); if (updateResetList) - m_resetList += WebPriceQuoteSource(*it); + d->m_resetList += WebPriceQuoteSource(*it); } - m_quoteSourceList->sortItems(); + d->ui->m_quoteSourceList->sortItems(); - QListWidgetItem* first = m_quoteSourceList->item(0); + QListWidgetItem* first = d->ui->m_quoteSourceList->item(0); if (first) - m_quoteSourceList->setCurrentItem(first); + d->ui->m_quoteSourceList->setCurrentItem(first); slotLoadWidgets(); - m_newButton->setEnabled((m_quoteSourceList->findItems(i18n("New Quote Source"), Qt::MatchExactly)).count() == 0); - connect(m_quoteSourceList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(slotEntryRenamed(QListWidgetItem*))); + d->ui->m_newButton->setEnabled((d->ui->m_quoteSourceList->findItems(i18n("New Quote Source"), Qt::MatchExactly)).count() == 0); + connect(d->ui->m_quoteSourceList, &QListWidget::itemChanged, this, &KSettingsOnlineQuotes::slotEntryRenamed); } void KSettingsOnlineQuotes::resetConfig() { + Q_D(KSettingsOnlineQuotes); QStringList::ConstIterator it; QStringList groups = WebPriceQuote::quoteSources(); // delete all currently defined entries for (it = groups.constBegin(); it != groups.constEnd(); ++it) { WebPriceQuoteSource(*it).remove(); } // and write back the one's from the reset list QList::ConstIterator itr; - for (itr = m_resetList.constBegin(); itr != m_resetList.constEnd(); ++itr) { + for (itr = d->m_resetList.constBegin(); itr != d->m_resetList.constEnd(); ++itr) { (*itr).write(); } loadList(); } void KSettingsOnlineQuotes::slotLoadWidgets() { - m_quoteInEditing = false; - QListWidgetItem* item = m_quoteSourceList->currentItem(); - - m_editURL->setEnabled(true); - m_editCSVURL->setEnabled(true); - m_editIdentifier->setEnabled(true); - m_editIdentifyBy->setEnabled(true); - m_editPrice->setEnabled(true); - m_editDate->setEnabled(true); - m_editDateFormat->setEnabled(true); - m_skipStripping->setEnabled(true); - m_dumpCSVProfile->setEnabled(true); - m_deleteButton->setEnabled(true); - m_editURL->setText(QString()); - m_editCSVURL->setText(QString()); - m_editIdentifier->setText(QString()); - m_editIdentifyBy->setCurrentIndex(WebPriceQuoteSource::identifyBy::Symbol); - m_editPrice->setText(QString()); - m_editDate->setText(QString()); - m_editDateFormat->setText(QString()); + Q_D(KSettingsOnlineQuotes); + d->m_quoteInEditing = false; + QListWidgetItem* item = d->ui->m_quoteSourceList->currentItem(); + + d->ui->m_editURL->setEnabled(true); + d->ui->m_editCSVURL->setEnabled(true); + d->ui->m_editIdentifier->setEnabled(true); + d->ui->m_editIdentifyBy->setEnabled(true); + d->ui->m_editPrice->setEnabled(true); + d->ui->m_editDate->setEnabled(true); + d->ui->m_editDateFormat->setEnabled(true); + d->ui->m_skipStripping->setEnabled(true); + d->ui->m_dumpCSVProfile->setEnabled(true); + d->ui->m_deleteButton->setEnabled(true); + d->ui->m_editURL->setText(QString()); + d->ui->m_editCSVURL->setText(QString()); + d->ui->m_editIdentifier->setText(QString()); + d->ui->m_editIdentifyBy->setCurrentIndex(WebPriceQuoteSource::identifyBy::Symbol); + d->ui->m_editPrice->setText(QString()); + d->ui->m_editDate->setText(QString()); + d->ui->m_editDateFormat->setText(QString()); if (item) { - m_currentItem = WebPriceQuoteSource(item->text()); - m_editURL->setText(m_currentItem.m_url); - m_editCSVURL->setText(m_currentItem.m_csvUrl); - m_editIdentifier->setText(m_currentItem.m_webID); - m_editIdentifyBy->setCurrentIndex(m_currentItem.m_webIDBy); - m_editPrice->setText(m_currentItem.m_price); - m_editDate->setText(m_currentItem.m_date); - m_editDateFormat->setText(m_currentItem.m_dateformat); - m_skipStripping->setChecked(m_currentItem.m_skipStripping); + d->m_currentItem = WebPriceQuoteSource(item->text()); + d->ui->m_editURL->setText(d->m_currentItem.m_url); + d->ui->m_editCSVURL->setText(d->m_currentItem.m_csvUrl); + d->ui->m_editIdentifier->setText(d->m_currentItem.m_webID); + d->ui->m_editIdentifyBy->setCurrentIndex(d->m_currentItem.m_webIDBy); + d->ui->m_editPrice->setText(d->m_currentItem.m_price); + d->ui->m_editDate->setText(d->m_currentItem.m_date); + d->ui->m_editDateFormat->setText(d->m_currentItem.m_dateformat); + d->ui->m_skipStripping->setChecked(d->m_currentItem.m_skipStripping); } else { - m_editURL->setEnabled(false); - m_editCSVURL->setEnabled(false); - m_editIdentifier->setEnabled(false); - m_editIdentifyBy->setEnabled(false); - m_editPrice->setEnabled(false); - m_editDate->setEnabled(false); - m_editDateFormat->setEnabled(false); - m_skipStripping->setEnabled(false); - m_dumpCSVProfile->setEnabled(false); - m_deleteButton->setEnabled(false); + d->ui->m_editURL->setEnabled(false); + d->ui->m_editCSVURL->setEnabled(false); + d->ui->m_editIdentifier->setEnabled(false); + d->ui->m_editIdentifyBy->setEnabled(false); + d->ui->m_editPrice->setEnabled(false); + d->ui->m_editDate->setEnabled(false); + d->ui->m_editDateFormat->setEnabled(false); + d->ui->m_skipStripping->setEnabled(false); + d->ui->m_dumpCSVProfile->setEnabled(false); + d->ui->m_deleteButton->setEnabled(false); } - m_updateButton->setEnabled(false); + d->ui->m_updateButton->setEnabled(false); } void KSettingsOnlineQuotes::slotEntryChanged() { - bool modified = m_editURL->text() != m_currentItem.m_url - || m_editCSVURL->text() != m_currentItem.m_csvUrl - || m_editIdentifier->text() != m_currentItem.m_webID - || m_editIdentifyBy->currentData().toInt() != static_cast(m_currentItem.m_webIDBy) - || m_editDate->text() != m_currentItem.m_date - || m_editDateFormat->text() != m_currentItem.m_dateformat - || m_editPrice->text() != m_currentItem.m_price - || m_skipStripping->isChecked() != m_currentItem.m_skipStripping; - - m_updateButton->setEnabled(modified); + Q_D(KSettingsOnlineQuotes); + bool modified = d->ui->m_editURL->text() != d->m_currentItem.m_url + || d->ui->m_editCSVURL->text() != d->m_currentItem.m_csvUrl + || d->ui->m_editIdentifier->text() != d->m_currentItem.m_webID + || d->ui->m_editIdentifyBy->currentData().toInt() != static_cast(d->m_currentItem.m_webIDBy) + || d->ui->m_editDate->text() != d->m_currentItem.m_date + || d->ui->m_editDateFormat->text() != d->m_currentItem.m_dateformat + || d->ui->m_editPrice->text() != d->m_currentItem.m_price + || d->ui->m_skipStripping->isChecked() != d->m_currentItem.m_skipStripping; + + d->ui->m_updateButton->setEnabled(modified); +} + +void KSettingsOnlineQuotes::slotEntryChanged(int) +{ + slotEntryChanged(); +} + +void KSettingsOnlineQuotes::slotEntryChanged(const QString&) +{ + slotEntryChanged(); +} + +void KSettingsOnlineQuotes::slotEntryChanged(bool) +{ + slotEntryChanged(); } void KSettingsOnlineQuotes::slotDumpCSVProfile() { + Q_D(KSettingsOnlineQuotes); KSharedConfigPtr config = CSVImporter::configFile(); PricesProfile profile; - profile.m_profileName = m_currentItem.m_name; + profile.m_profileName = d->m_currentItem.m_name; profile.m_profileType = Profile::StockPrices; bool profileExists = false; bool writeProfile = true; if (profile.readSettings(config)) profileExists = true; else { profile.m_profileType = Profile::CurrencyPrices; if (profile.readSettings(config)) profileExists = true; } if (profileExists) writeProfile = (KMessageBox::questionYesNoCancel(this, i18n("CSV profile %1 already exists.
" "Do you want to overwrite it?", - m_currentItem.m_name), + d->m_currentItem.m_name), i18n("CSV Profile Already Exists")) == KMessageBox::Yes ? true : false); if (writeProfile) { QMap quoteSources = WebPriceQuote::defaultCSVQuoteSources(); - profile = quoteSources.value(m_currentItem.m_name); - if (profile.m_profileName.compare(m_currentItem.m_name, Qt::CaseInsensitive) == 0) { + profile = quoteSources.value(d->m_currentItem.m_name); + if (profile.m_profileName.compare(d->m_currentItem.m_name, Qt::CaseInsensitive) == 0) { profile.writeSettings(config); CSVImporter::profilesAction(profile.type(), ProfileAction::Add, profile.m_profileName, profile.m_profileName); } } CSVImporter::profilesAction(profile.type(), ProfileAction::UpdateLastUsed, profile.m_profileName, profile.m_profileName); } void KSettingsOnlineQuotes::slotUpdateEntry() { - m_currentItem.m_url = m_editURL->text(); - m_currentItem.m_csvUrl = m_editCSVURL->text(); - m_currentItem.m_webID = m_editIdentifier->text(); - m_currentItem.m_webIDBy = static_cast(m_editIdentifyBy->currentData().toInt()); - m_currentItem.m_date = m_editDate->text(); - m_currentItem.m_dateformat = m_editDateFormat->text(); - m_currentItem.m_price = m_editPrice->text(); - m_currentItem.m_skipStripping = m_skipStripping->isChecked(); - m_currentItem.write(); + Q_D(KSettingsOnlineQuotes); + d->m_currentItem.m_url = d->ui->m_editURL->text(); + d->m_currentItem.m_csvUrl = d->ui->m_editCSVURL->text(); + d->m_currentItem.m_webID = d->ui->m_editIdentifier->text(); + d->m_currentItem.m_webIDBy = static_cast(d->ui->m_editIdentifyBy->currentData().toInt()); + d->m_currentItem.m_date = d->ui->m_editDate->text(); + d->m_currentItem.m_dateformat = d->ui->m_editDateFormat->text(); + d->m_currentItem.m_price = d->ui->m_editPrice->text(); + d->m_currentItem.m_skipStripping = d->ui->m_skipStripping->isChecked(); + d->m_currentItem.write(); slotEntryChanged(); } void KSettingsOnlineQuotes::slotNewEntry() { + Q_D(KSettingsOnlineQuotes); WebPriceQuoteSource newSource(i18n("New Quote Source")); newSource.write(); loadList(); - QListWidgetItem* item = m_quoteSourceList->findItems(i18n("New Quote Source"), Qt::MatchExactly).at(0); + QListWidgetItem* item = d->ui->m_quoteSourceList->findItems(i18n("New Quote Source"), Qt::MatchExactly).at(0); if (item) { - m_quoteSourceList->setCurrentItem(item); + d->ui->m_quoteSourceList->setCurrentItem(item); slotLoadWidgets(); } } void KSettingsOnlineQuotes::slotDeleteEntry() { + Q_D(KSettingsOnlineQuotes); // first check if no security is using this online source - QList securities = MyMoneyFile::instance()->securityList(); + auto securities = MyMoneyFile::instance()->securityList(); foreach(const auto security, securities) { - if (security.value(QStringLiteral("kmm-online-source")).compare(m_currentItem.m_name) == 0) { + if (security.value(QStringLiteral("kmm-online-source")).compare(d->m_currentItem.m_name) == 0) { if (KMessageBox::questionYesNo(this, i18n("Security %1 uses this quote source.
" "Do you really want to remove it?", security.name()), i18n("Delete quote source")) == KMessageBox::Yes) break; // webpricequote can handle missing online quotes, so proceed without any extra action else return; } } // remove online source from webpricequote... - m_currentItem.remove(); + d->m_currentItem.remove(); // ...and from setting's list - int row = m_quoteSourceList->currentRow(); - QListWidgetItem *item = m_quoteSourceList->takeItem(row); + auto row = d->ui->m_quoteSourceList->currentRow(); + QListWidgetItem *item = d->ui->m_quoteSourceList->takeItem(row); if (item) delete item; item = nullptr; - int count = m_quoteSourceList->count(); + int count = d->ui->m_quoteSourceList->count(); if (row < count) // select next available entry... - item = m_quoteSourceList->item(row); + item = d->ui->m_quoteSourceList->item(row); else if (row >= count && count > 0) // ...or last entry if this was the last entry... - item = m_quoteSourceList->item(count - 1); + item = d->ui->m_quoteSourceList->item(count - 1); if (item) { - m_quoteSourceList->setCurrentItem(item); + d->ui->m_quoteSourceList->setCurrentItem(item); slotLoadWidgets(); } } void KSettingsOnlineQuotes::slotStartRename(QListWidgetItem* item) { - m_quoteInEditing = true; - m_quoteSourceList->editItem(item); + Q_D(KSettingsOnlineQuotes); + d->m_quoteInEditing = true; + d->ui->m_quoteSourceList->editItem(item); } void KSettingsOnlineQuotes::slotEntryRenamed(QListWidgetItem* item) { + Q_D(KSettingsOnlineQuotes); //if there is no current item selected, exit - if (m_quoteInEditing == false || !m_quoteSourceList->currentItem() || item != m_quoteSourceList->currentItem()) + if (d->m_quoteInEditing == false || !d->ui->m_quoteSourceList->currentItem() || item != d->ui->m_quoteSourceList->currentItem()) return; - m_quoteInEditing = false; + d->m_quoteInEditing = false; QString text = item->text(); int nameCount = 0; - for (int i = 0; i < m_quoteSourceList->count(); ++i) { - if (m_quoteSourceList->item(i)->text() == text) + for (auto i = 0; i < d->ui->m_quoteSourceList->count(); ++i) { + if (d->ui->m_quoteSourceList->item(i)->text() == text) ++nameCount; } // Make sure we get a non-empty and unique name if (text.length() > 0 && nameCount == 1) { - m_currentItem.rename(text); + d->m_currentItem.rename(text); } else { - item->setText(m_currentItem.m_name); + item->setText(d->m_currentItem.m_name); } - m_quoteSourceList->sortItems(); - m_newButton->setEnabled(m_quoteSourceList->findItems(i18n("New Quote Source"), Qt::MatchExactly).count() == 0); + d->ui->m_quoteSourceList->sortItems(); + d->ui->m_newButton->setEnabled(d->ui->m_quoteSourceList->findItems(i18n("New Quote Source"), Qt::MatchExactly).count() == 0); } diff --git a/kmymoney/dialogs/settings/ksettingsonlinequotes.h b/kmymoney/dialogs/settings/ksettingsonlinequotes.h index d15fe6199..13d10243f 100644 --- a/kmymoney/dialogs/settings/ksettingsonlinequotes.h +++ b/kmymoney/dialogs/settings/ksettingsonlinequotes.h @@ -1,74 +1,70 @@ /*************************************************************************** ksettingsonlinequotes.h ------------------- begin : Thu Dec 30 2004 copyright : (C) 2004 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSETTINGSONLINEQUOTES_H #define KSETTINGSONLINEQUOTES_H // ---------------------------------------------------------------------------- // QT Includes -#include +#include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ksettingsonlinequotesdecl.h" -#include "kmymoney/converter/webpricequote.h" +class QListWidgetItem; - -class KSettingsOnlineQuotesDecl : public QWidget, public Ui::KSettingsOnlineQuotesDecl -{ -public: - KSettingsOnlineQuotesDecl(QWidget *parent) : QWidget(parent) { - setupUi(this); - } -}; - -class KSettingsOnlineQuotes : public KSettingsOnlineQuotesDecl +class KSettingsOnlineQuotesPrivate; +class KSettingsOnlineQuotes : public QWidget { Q_OBJECT + Q_DISABLE_COPY(KSettingsOnlineQuotes) + public: - KSettingsOnlineQuotes(QWidget* parent = 0); - virtual ~KSettingsOnlineQuotes() {} + explicit KSettingsOnlineQuotes(QWidget* parent = nullptr); + ~KSettingsOnlineQuotes(); void writeConfig() {} void readConfig() {} void resetConfig(); protected slots: void slotDumpCSVProfile(); void slotUpdateEntry(); void slotLoadWidgets(); void slotEntryChanged(); + void slotEntryChanged(int idx); + void slotEntryChanged(const QString& str); + void slotEntryChanged(bool b); void slotNewEntry(); void slotDeleteEntry(); void slotEntryRenamed(QListWidgetItem* item); void slotStartRename(QListWidgetItem* item); protected: void loadList(const bool updateResetList = false); private: - QList m_resetList; - WebPriceQuoteSource m_currentItem; - bool m_quoteInEditing; + KSettingsOnlineQuotesPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KSettingsOnlineQuotes) }; #endif diff --git a/kmymoney/dialogs/settings/ksettingsonlinequotesdecl.ui b/kmymoney/dialogs/settings/ksettingsonlinequotes.ui similarity index 90% rename from kmymoney/dialogs/settings/ksettingsonlinequotesdecl.ui rename to kmymoney/dialogs/settings/ksettingsonlinequotes.ui index eb268a235..ff0748056 100644 --- a/kmymoney/dialogs/settings/ksettingsonlinequotesdecl.ui +++ b/kmymoney/dialogs/settings/ksettingsonlinequotes.ui @@ -1,235 +1,253 @@ - KSettingsOnlineQuotesDecl - + KSettingsOnlineQuotes + 0 0 512 592 0 0 Online Quotes 0 0 <i>Enter regular expressions which can be used to parse the data returned from the URL entered above. The symbol, price, and date must be found in the quote data to be usable. You may also try the KMyMoney user's mailinglist at <a href="mailto:kmymoney@kde.org">kmymoney@kde.org</a> to find what settings work for other users in your country.</i> Details Date Format false Identifier false Regular Expression to extract the identifier from the downloaded data Price false Regular Expression to extract the date from the downloaded data Date false URL false CSV URL URL to be used to download the quote Enter the URL from which stock quotes will be fetched. <b>%1</b> will be replaced with the symbol for the security being quoted. For currency conversions, <b>%2</b> will be replaced with the currency to be quoted and <b>%1</b> with the currency the quote is based on. Regular Expression to extract the date from the downloaded data Regular Expression to extract the price from the downloaded data <p>For easier processing of the data returned by the online source, KMyMoney usually strips unused parts before it is parsed with the regular expressions. If matching of the fields relies on those items, then use this option to turn stripping off.</p> <p>The following items are usually removed by stripping: <ul> <li>HTML tags such as <b>&lt;tag&gt;</b></li> <li>& encoded characters such as <b>&amp;nbsp;</b></li> <li>duplicate whitespace</li> </ul> </p> Skip HTML stripping Identify by + + Create a new source entry for online quotes + + + Use this to create a new entry for online quotes + New + + Delete the selected source entry + + + Use this to delete the selected online source entry + Delete Qt::Horizontal QSizePolicy::Expanding 240 20 Dumps CSV profile used for importing downloaded prices, which can be customized by user in CSV Importer. Dump CSV + + Accepts the entered data and stores it + + + Use this to accept the modified data. + Update KLineEdit QLineEdit
klineedit.h
diff --git a/kmymoney/dialogs/settings/ksettingsregister.cpp b/kmymoney/dialogs/settings/ksettingsregister.cpp index ccb485914..a690f4f32 100644 --- a/kmymoney/dialogs/settings/ksettingsregister.cpp +++ b/kmymoney/dialogs/settings/ksettingsregister.cpp @@ -1,73 +1,78 @@ /*************************************************************************** ksettingsregister.cpp -------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "ksettingsregister.h" // ---------------------------------------------------------------------------- // QT Includes // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_ksettingsregister.h" + KSettingsRegister::KSettingsRegister(QWidget* parent) : - KSettingsRegisterDecl(parent) + QWidget(parent), + ui(new Ui::KSettingsRegister) { - + ui->setupUi(this); // hide the internally used text fields - kcfg_sortNormalView->hide(); - kcfg_sortReconcileView->hide(); - kcfg_sortSearchView->hide(); + ui->kcfg_sortNormalView->hide(); + ui->kcfg_sortReconcileView->hide(); + ui->kcfg_sortSearchView->hide(); // setup connections, so that the sort optios get loaded once the edit fields are filled - connect(kcfg_sortNormalView, SIGNAL(textChanged(QString)), this, SLOT(slotLoadNormal(QString))); - connect(kcfg_sortReconcileView, SIGNAL(textChanged(QString)), this, SLOT(slotLoadReconcile(QString))); - connect(kcfg_sortSearchView, SIGNAL(textChanged(QString)), this, SLOT(slotLoadSearch(QString))); + connect(ui->kcfg_sortNormalView, &QLineEdit::textChanged, this, &KSettingsRegister::slotLoadNormal); + connect(ui->kcfg_sortReconcileView, &QLineEdit::textChanged, this, &KSettingsRegister::slotLoadReconcile); + connect(ui->kcfg_sortSearchView, &QLineEdit::textChanged, this, &KSettingsRegister::slotLoadSearch); // setup connections, so that changes by the user are forwarded to the (hidden) edit fields - connect(m_sortNormalView, SIGNAL(settingsChanged(QString)), kcfg_sortNormalView, SLOT(setText(QString))); - connect(m_sortReconcileView, SIGNAL(settingsChanged(QString)), kcfg_sortReconcileView, SLOT(setText(QString))); - connect(m_sortSearchView, SIGNAL(settingsChanged(QString)), kcfg_sortSearchView, SLOT(setText(QString))); + connect(ui->m_sortNormalView, &TransactionSortOption::settingsChanged, ui->kcfg_sortNormalView, &KLineEdit::setText); + connect(ui->m_sortReconcileView, &TransactionSortOption::settingsChanged, ui->kcfg_sortReconcileView, &KLineEdit::setText); + connect(ui->m_sortSearchView, &TransactionSortOption::settingsChanged, ui->kcfg_sortSearchView, &KLineEdit::setText); } KSettingsRegister::~KSettingsRegister() { + delete ui; } void KSettingsRegister::slotLoadNormal(const QString& text) { // only need this once - disconnect(kcfg_sortNormalView, SIGNAL(textChanged(QString)), this, SLOT(slotLoadNormal(QString))); - m_sortNormalView->setSettings(text); + disconnect(ui->kcfg_sortNormalView, &QLineEdit::textChanged, this, &KSettingsRegister::slotLoadNormal); + ui->m_sortNormalView->setSettings(text); } void KSettingsRegister::slotLoadReconcile(const QString& text) { // only need this once - disconnect(kcfg_sortReconcileView, SIGNAL(textChanged(QString)), this, SLOT(slotLoadReconcile(QString))); - m_sortReconcileView->setSettings(text); + disconnect(ui->kcfg_sortReconcileView, &QLineEdit::textChanged, this, &KSettingsRegister::slotLoadReconcile); + ui->m_sortReconcileView->setSettings(text); } void KSettingsRegister::slotLoadSearch(const QString& text) { // only need this once - disconnect(kcfg_sortSearchView, SIGNAL(textChanged(QString)), this, SLOT(slotLoadSearch(QString))); - m_sortSearchView->setSettings(text); + disconnect(ui->kcfg_sortSearchView, &QLineEdit::textChanged, this, &KSettingsRegister::slotLoadSearch); + ui->m_sortSearchView->setSettings(text); } diff --git a/kmymoney/dialogs/settings/ksettingsregister.h b/kmymoney/dialogs/settings/ksettingsregister.h index 1e40e2357..968eb4611 100644 --- a/kmymoney/dialogs/settings/ksettingsregister.h +++ b/kmymoney/dialogs/settings/ksettingsregister.h @@ -1,54 +1,53 @@ /*************************************************************************** ksettingsregister.h ------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSETTINGSREGISTER_H #define KSETTINGSREGISTER_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ksettingsregisterdecl.h" - -class KSettingsRegisterDecl : public QWidget, public Ui::KSettingsRegisterDecl -{ -public: - KSettingsRegisterDecl(QWidget *parent) : QWidget(parent) { - setupUi(this); - } -}; - +namespace Ui { class KSettingsRegister; } -class KSettingsRegister : public KSettingsRegisterDecl +class KSettingsRegister : public QWidget { Q_OBJECT + Q_DISABLE_COPY(KSettingsRegister) public: - KSettingsRegister(QWidget* parent = 0); + explicit KSettingsRegister(QWidget* parent = nullptr); ~KSettingsRegister(); protected slots: void slotLoadNormal(const QString& text); void slotLoadReconcile(const QString& text); void slotLoadSearch(const QString& text); + +private: + Ui::KSettingsRegister *ui; + }; #endif diff --git a/kmymoney/dialogs/settings/ksettingsregisterdecl.ui b/kmymoney/dialogs/settings/ksettingsregister.ui similarity index 99% rename from kmymoney/dialogs/settings/ksettingsregisterdecl.ui rename to kmymoney/dialogs/settings/ksettingsregister.ui index 447f88c0e..be5a9ad9f 100644 --- a/kmymoney/dialogs/settings/ksettingsregisterdecl.ui +++ b/kmymoney/dialogs/settings/ksettingsregister.ui @@ -1,506 +1,506 @@ - KSettingsRegisterDecl - + KSettingsRegister + 0 0 632 403 Register settings Display Show a grid in the register Show all register entries in full detail Use the ledger lens Using the ledger lens shows the details for the transaction that has focus in the ledger. Usually, when using the transaction form, only a one line summary is displayed for each transaction as the details are shown in the form. Show transaction form Always show a No. field Show group header between transactions Draws a larger header above each group of transactions. The grouping depends on the current sort order. Show header for the previous and current fiscal year 20 40 QSizePolicy::Expanding Qt::Vertical Sorting Normal view Reconciliation view Search view Use the <i>left</i> and <i>right</i> buttons to add and remove sort options. Use the <i>up</i> and <i>down</i> buttons to modify the sort order. Double-Click a selected entry to toggle the sort order between <i>ascending</i> and <i>descending</i>. true Data entry Insert transaction type into No. field for new transactions Auto increment check number Keep changes when selecting a different transaction/split Use Enter to move between fields Match names from start Mark this option, if you always want to match names e.g. for payees from the start. If unset, any substring is matched. Automatic reconciliation After entering the reconciliation data automatically detect the transactions that match that data (in some cases it might be not possible to do that). Default reconciliation state false Default reconciliation state for transactions entered during reconciliation of an account Not reconciled Cleared Reconciled 31 20 QSizePolicy::Expanding Qt::Horizontal Autofill -1 No Autofill Do not auto-fill transaction data at all. Same transaction if amount differs less than Collect all transactions for the given payee. Treat all transactions that refer to the same category and have an amount with +/- X % as identical. If more than one transaction is found, a list of them is presented to the user. Selecting 0% will list all transactions. 100 10 Two transactions are usually treated identical for autofill, if they refer the same accounts. They are treated as different transactions though, when their amount varies by more than the percentage given here. percent. false With previously most often used transaction for the payee The data of the last transaction assigned to the category used most often for this payee is autofilled into the transaction editor. Use memos from previous transaction If this option is checked the memos from the previous transaction will be used otherwise the memos will not be considered when the transaction is autofilled. 20 20 QSizePolicy::Expanding Qt::Vertical Import Match transactions within days false UpDownArrows 99 0 4 Search for matching transactions within the range of the posting date of the imported transaction +/- the number of given days. 61 20 QSizePolicy::Expanding Qt::Horizontal Ask for a new payee's default category Whenever a new payee is detected during import of a statement, the user will be asked to assign a default category for this user when this option is selected. 20 60 QSizePolicy::Expanding Qt::Vertical QSpinBox QSpinBox
knuminput.h
TransactionSortOption QWidget
transactionsortoptionimpl.h
KComboBox QComboBox
kcombobox.h
QTabWidget QTabWidget
ktabwidget.h
diff --git a/kmymoney/dialogs/settings/ksettingsreports.cpp b/kmymoney/dialogs/settings/ksettingsreports.cpp index ad2dc9fb3..d49a282f0 100644 --- a/kmymoney/dialogs/settings/ksettingsreports.cpp +++ b/kmymoney/dialogs/settings/ksettingsreports.cpp @@ -1,172 +1,190 @@ /*************************************************************************** ksettingsreports.cpp -------------------- copyright : (C) 2010 by Bernd Gonsior email : bernd.gonsior@googlemail.com + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "ksettingsreports.h" // ---------------------------------------------------------------------------- // QT Includes #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include // ---------------------------------------------------------------------------- // Project Includes +#include "ui_ksettingsreports.h" + #include "kmymoneyglobalsettings.h" -class KSettingsReports::Private +class KSettingsReportsPrivate { + Q_DISABLE_COPY(KSettingsReportsPrivate) + public: + KSettingsReportsPrivate() : + ui(new Ui::KSettingsReports), + m_fileKLineEdit(nullptr) + { + } - Private() : m_fileKLineEdit(0) {} + ~KSettingsReportsPrivate() + { + delete ui; + } - ~Private() {} /** * Collector for both signals * urlSelected and editingFinished. * * Only shows a warning * if the selected file * is not a readable plain file - * and only one time. * * @param[in] css css file name * * @see KSettingsReports#slotCssUrlSelected * @see KSettingsReports#slotEditingFinished */ void checkCssFile(QString& css) { if (css == m_cssFileOld) { // do not check again to avoid emitting a warning more than 1 time return; } m_cssFileOld = css; QFileInfo* info = new QFileInfo(css); if (!info->exists()) { KMessageBox::sorry(0, i18n("File %1 does not exist", css)); return; } QList warnings; if (!info->isFile()) { warnings.append(i18n("it is not a plain file")); } if (!info->isReadable()) { warnings.append(i18n("it is not readable")); } if (info->size() < 1) { warnings.append(i18n("it is empty")); } if (warnings.size() < 1) { // no warnings, fine return; } QString out = i18np("There is a problem with file %1", "There are problems with file %1", css); QList::const_iterator i; for (i = warnings.constBegin(); i != warnings.constEnd(); ++i) { out += '\n' + *i; } KMessageBox::sorry(0, out); } + Ui::KSettingsReports *ui; /** * Old value of css file to avoid warnings * when a signal is emitted * but the value itself did not change. */ QString m_cssFileOld; /** * Pointer to the KLineEdit of the KFileDialog which we need * to receive signal editingFinished. */ KLineEdit* m_fileKLineEdit; }; KSettingsReports::KSettingsReports(QWidget* parent) : - KSettingsReportsDecl(parent), - d(new Private) + QWidget(parent), + d_ptr(new KSettingsReportsPrivate) { + Q_D(KSettingsReports); + d->ui->setupUi(this); // keep initial (default) css file in mind d->m_cssFileOld = KMyMoneyGlobalSettings::cssFileDefault(); // set default css file in ksettingsreports dialog - kcfg_CssFileDefault->setUrl(QUrl::fromLocalFile(KMyMoneyGlobalSettings::cssFileDefault())); + d->ui->kcfg_CssFileDefault->setUrl(QUrl::fromLocalFile(KMyMoneyGlobalSettings::cssFileDefault())); - d->m_fileKLineEdit = kcfg_CssFileDefault->lineEdit(); + d->m_fileKLineEdit = d->ui->kcfg_CssFileDefault->lineEdit(); - connect(kcfg_CssFileDefault, SIGNAL(urlSelected(QUrl)), - this, SLOT(slotCssUrlSelected(QUrl))); + connect(d->ui->kcfg_CssFileDefault, &KUrlRequester::urlSelected, + this, &KSettingsReports::slotCssUrlSelected); - connect(d->m_fileKLineEdit, SIGNAL(editingFinished()), - this, SLOT(slotEditingFinished())); + connect(d->m_fileKLineEdit, &QLineEdit::editingFinished, + this, &KSettingsReports::slotEditingFinished); } KSettingsReports::~KSettingsReports() { + Q_D(KSettingsReports); delete d; } /** * Receiver for signal urlSelected. * * Signal urlSelected only is emitted * when a file is selected with the file chooser. * * @param[in] cssUrl url of css file * * @see KSettingsReports#Private#checkCssFile */ void KSettingsReports::slotCssUrlSelected(const QUrl &cssUrl) { - QString css = cssUrl.toLocalFile(); + Q_D(KSettingsReports); + auto css = cssUrl.toLocalFile(); d->checkCssFile(css); } /** * Receiver for signal editingFinished. * * Signal editingFinished is emitted * on focus out only, * not when a file is selected with the file chooser. * * @see KSettingsReports#Private#checkCssFile */ void KSettingsReports::slotEditingFinished() { - QString txt = d->m_fileKLineEdit->text(); + Q_D(KSettingsReports); + auto txt = d->m_fileKLineEdit->text(); d->checkCssFile(txt); } diff --git a/kmymoney/dialogs/settings/ksettingsreports.h b/kmymoney/dialogs/settings/ksettingsreports.h index 1e967f116..2933e7fec 100644 --- a/kmymoney/dialogs/settings/ksettingsreports.h +++ b/kmymoney/dialogs/settings/ksettingsreports.h @@ -1,60 +1,50 @@ /*************************************************************************** ksettingsreports.h ------------------- copyright : (C) 2010 by Bernd Gonsior email : bernd.gonsior@googlemail.com + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSETTINGSREPORTS_H #define KSETTINGSREPORTS_H // ---------------------------------------------------------------------------- // QT Includes #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ksettingsreportsdecl.h" - -class KSettingsReportsDecl : public QWidget, public Ui::KSettingsReportsDecl -{ -public: - KSettingsReportsDecl(QWidget *parent) : QWidget(parent) { - setupUi(this); - } -}; - -class KSettingsReports : public KSettingsReportsDecl +class KSettingsReportsPrivate; +class KSettingsReports : public QWidget { Q_OBJECT + Q_DISABLE_COPY(KSettingsReports) public: - KSettingsReports(QWidget* parent = 0); + explicit KSettingsReports(QWidget* parent = nullptr); ~KSettingsReports(); protected slots: void slotCssUrlSelected(const QUrl&); void slotEditingFinished(); private: - /// \internal d-pointer class. - class Private; - /// \internal d-pointer instance. - Private* const d; - + KSettingsReportsPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KSettingsReports) }; #endif diff --git a/kmymoney/dialogs/settings/ksettingsreportsdecl.ui b/kmymoney/dialogs/settings/ksettingsreports.ui similarity index 98% rename from kmymoney/dialogs/settings/ksettingsreportsdecl.ui rename to kmymoney/dialogs/settings/ksettingsreports.ui index e0b240bea..7558e3a9d 100644 --- a/kmymoney/dialogs/settings/ksettingsreportsdecl.ui +++ b/kmymoney/dialogs/settings/ksettingsreports.ui @@ -1,194 +1,194 @@ - KSettingsReportsDecl - + KSettingsReports + 0 0 614 468 Report Settings Maximum number of legend items to display maximum number of items in diagram legends Qt::Horizontal 40 20 Charts line width Line width for diagrams, in pixels Qt::Horizontal 40 20 Charts palette 0 Default Rainbow Subdued Qt::Horizontal 40 20 Default CSS file default style sheet *.css|CSS files *|All files text Qt::Vertical 20 40 QSpinBox QSpinBox
knuminput.h
KUrlRequester QFrame
kurlrequester.h
KComboBox QComboBox
kcombobox.h
kcfg_MaximumLegendItems kcfg_LineWidth
diff --git a/kmymoney/dialogs/settings/ksettingsschedules.cpp b/kmymoney/dialogs/settings/ksettingsschedules.cpp index 82d7ae156..5caff996f 100644 --- a/kmymoney/dialogs/settings/ksettingsschedules.cpp +++ b/kmymoney/dialogs/settings/ksettingsschedules.cpp @@ -1,101 +1,131 @@ /*************************************************************************** ksettingsschedules.cpp -------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #include #include "ksettingsschedules.h" // ---------------------------------------------------------------------------- // QT Includes // ---------------------------------------------------------------------------- // KDE Includes #include #ifdef KF5Holidays_FOUND #include #include using namespace KHolidays; #endif // ---------------------------------------------------------------------------- // Project Includes -#include "kmymoney/kmymoneyglobalsettings.h" +#include "ui_ksettingsschedules.h" + + +class KSettingsSchedulesPrivate +{ + Q_DISABLE_COPY(KSettingsSchedulesPrivate) + +public: + KSettingsSchedulesPrivate() : + ui(new Ui::KSettingsSchedules) + { + } + + ~KSettingsSchedulesPrivate() + { + delete ui; + } + + Ui::KSettingsSchedules *ui; + QMap m_regionMap; +}; KSettingsSchedules::KSettingsSchedules(QWidget* parent) : - KSettingsSchedulesDecl(parent) + QWidget(parent), + d_ptr(new KSettingsSchedulesPrivate) { + Q_D(KSettingsSchedules); + d->ui->setupUi(this); // hide the internally used holidayRegion field - kcfg_HolidayRegion->hide(); + d->ui->kcfg_HolidayRegion->hide(); loadList(); // setup connections so that region gets selected once field is filled - connect(kcfg_HolidayRegion, SIGNAL(textChanged(QString)), this, SLOT(slotLoadRegion(QString))); + connect(d->ui->kcfg_HolidayRegion, &QLineEdit::textChanged, this, &KSettingsSchedules::slotLoadRegion); // setup connections so that changes are forwarded to the field - connect(m_holidayRegion, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotSetRegion(QString))); + connect(d->ui->m_holidayRegion, static_cast(&QComboBox::currentIndexChanged), this, &KSettingsSchedules::slotSetRegion); +} + +KSettingsSchedules::~KSettingsSchedules() +{ + Q_D(KSettingsSchedules); + delete d; } void KSettingsSchedules::loadList() { + Q_D(KSettingsSchedules); QStringList regions; #ifdef KF5Holidays_FOUND QStringList regionCodes = HolidayRegion::regionCodes(); foreach (const QString ®ionCode, regionCodes) { QString regionName = HolidayRegion::name(regionCode); QLocale langLocale(HolidayRegion::languageCode(regionCode)); QString languageName = QLocale().languageToString(langLocale.language()); QString region = languageName.isEmpty() ? regionName : i18nc("Holiday region (region language)", "%1 (%2)", regionName, languageName); - m_regionMap[region] = regionCode; + d->m_regionMap[region] = regionCode; regions << region; } regions.sort(); #endif - m_regionMap[m_holidayRegion->itemText(0)] = ""; - m_holidayRegion->insertItems(1, regions); + d->m_regionMap[d->ui->m_holidayRegion->itemText(0)] = QString(); + d->ui->m_holidayRegion->insertItems(1, regions); } void KSettingsSchedules::slotSetRegion(const QString ®ion) { - kcfg_HolidayRegion->setText(m_regionMap[region]); + Q_D(KSettingsSchedules); + d->ui->kcfg_HolidayRegion->setText(d->m_regionMap[region]); } void KSettingsSchedules::slotLoadRegion(const QString ®ion) { + Q_D(KSettingsSchedules); // only need this once - disconnect(kcfg_HolidayRegion, &KLineEdit::textChanged, this, &KSettingsSchedules::slotLoadRegion); - int i = 0; + disconnect(d->ui->kcfg_HolidayRegion, &KLineEdit::textChanged, this, &KSettingsSchedules::slotLoadRegion); + auto i = 0; if (!region.isEmpty()) - i = m_holidayRegion->findText(m_regionMap.key(region)); - if ((i > -1) && (i != m_holidayRegion->currentIndex())) { - m_holidayRegion->blockSignals(true); - m_holidayRegion->setCurrentIndex(i); - m_holidayRegion->blockSignals(false); + i = d->ui->m_holidayRegion->findText(d->m_regionMap.key(region)); + if ((i > -1) && (i != d->ui->m_holidayRegion->currentIndex())) { + d->ui->m_holidayRegion->blockSignals(true); + d->ui->m_holidayRegion->setCurrentIndex(i); + d->ui->m_holidayRegion->blockSignals(false); } } void KSettingsSchedules::slotResetRegion() { - slotLoadRegion(kcfg_HolidayRegion->text()); -} - -KSettingsSchedules::~KSettingsSchedules() -{ + Q_D(KSettingsSchedules); + slotLoadRegion(d->ui->kcfg_HolidayRegion->text()); } diff --git a/kmymoney/dialogs/settings/ksettingsschedules.h b/kmymoney/dialogs/settings/ksettingsschedules.h index 5e523a583..4726c0e3e 100644 --- a/kmymoney/dialogs/settings/ksettingsschedules.h +++ b/kmymoney/dialogs/settings/ksettingsschedules.h @@ -1,63 +1,57 @@ /*************************************************************************** ksettingsschedules.h ------------------- copyright : (C) 2005 by Thomas Baumgart email : ipwizard@users.sourceforge.net + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef KSETTINGSSCHEDULES_H #define KSETTINGSSCHEDULES_H // ---------------------------------------------------------------------------- // QT Includes +#include + // ---------------------------------------------------------------------------- // KDE Includes - // ---------------------------------------------------------------------------- // Project Includes -#include "ui_ksettingsschedulesdecl.h" - -class KSettingsSchedulesDecl : public QWidget, public Ui::KSettingsSchedulesDecl -{ -public: - KSettingsSchedulesDecl(QWidget *parent) : QWidget(parent) { - setupUi(this); - } -}; - - -class KSettingsSchedules : public KSettingsSchedulesDecl +class KSettingsSchedulesPrivate; +class KSettingsSchedules : public QWidget { Q_OBJECT + Q_DISABLE_COPY(KSettingsSchedules) public: - KSettingsSchedules(QWidget* parent = 0); + explicit KSettingsSchedules(QWidget* parent = nullptr); ~KSettingsSchedules(); public slots: void slotResetRegion(); protected slots: void slotLoadRegion(const QString ®ion); void slotSetRegion(const QString ®ion); protected: void loadList(); private: - QMap m_regionMap; + KSettingsSchedulesPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KSettingsSchedules) }; #endif diff --git a/kmymoney/dialogs/settings/ksettingsschedulesdecl.ui b/kmymoney/dialogs/settings/ksettingsschedules.ui similarity index 98% rename from kmymoney/dialogs/settings/ksettingsschedulesdecl.ui rename to kmymoney/dialogs/settings/ksettingsschedules.ui index 164f5a483..42dce4688 100644 --- a/kmymoney/dialogs/settings/ksettingsschedulesdecl.ui +++ b/kmymoney/dialogs/settings/ksettingsschedules.ui @@ -1,196 +1,196 @@ - KSettingsSchedulesDecl - + KSettingsSchedules + 0 0 482 236 Schedule Settings Startup options Check schedules on startup false QFrame::StyledPanel QFrame::Raised Enter transactions this number of days in advance false 999 Processing Days Use holiday calendar for region false (None) Qt::Horizontal QSizePolicy::Expanding 282 17 Number of days to preview schedules in ledger false 999 41 21 QSizePolicy::Expanding Qt::Horizontal 20 40 QSizePolicy::Expanding Qt::Vertical QSpinBox QSpinBox
knuminput.h
KComboBox QComboBox
kcombobox.h
KLineEdit QLineEdit
klineedit.h
kcfg_CheckSchedule toggled(bool) m_dayCountFrame setEnabled(bool)
diff --git a/kmymoney/dialogs/splitadjustdialog.cpp b/kmymoney/dialogs/splitadjustdialog.cpp index d29aa2a58..94dd6104a 100644 --- a/kmymoney/dialogs/splitadjustdialog.cpp +++ b/kmymoney/dialogs/splitadjustdialog.cpp @@ -1,78 +1,79 @@ /*************************************************************************** splitadjustdialog.cpp ------------------- begin : Sat Jul 23 2016 copyright : (C) 2016 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "splitadjustdialog.h" #include "ui_splitadjustdialog.h" #include class SplitAdjustDialog::Private { public: Private() : ui(new Ui_SplitAdjustDialog) {} Ui_SplitAdjustDialog* ui; QButtonGroup* buttonGroup; }; SplitAdjustDialog::SplitAdjustDialog(QWidget* parent, Qt::WindowFlags f) : QDialog(parent, f) , d(new Private) { d->ui->setupUi(this); d->buttonGroup = new QButtonGroup(this); d->buttonGroup->addButton(d->ui->continueBtn, SplitAdjustContinue); d->buttonGroup->addButton(d->ui->changeBtn, SplitAdjustChange); d->buttonGroup->addButton(d->ui->distributeBtn, SplitAdjustDistribute); d->buttonGroup->addButton(d->ui->leaveBtn, SplitAdjustLeaveAsIs); } SplitAdjustDialog::~SplitAdjustDialog() { } SplitAdjustDialog::Options SplitAdjustDialog::selectedOption() const { return static_cast(d->buttonGroup->checkedId()); } void SplitAdjustDialog::setValues(QString transactionSum, QString splitSum, QString diff, int splitCount) { // now modify the text items of the dialog to contain the correct values QString q = i18n("The total amount of this transaction is %1 while " "the sum of the splits is %2. The remaining %3 are " "unassigned.", transactionSum, splitSum, diff); d->ui->explanation->setText(q); q = i18n("Change &total amount of transaction to %1.", splitSum); d->ui->changeBtn->setText(q); q = i18n("&Distribute difference of %1 among all splits.", diff); d->ui->distributeBtn->setText(q); // FIXME remove the following line once distribution among // all splits is implemented d->ui->distributeBtn->hide(); // if we have only two splits left, we don't allow leaving sth. unassigned. if (splitCount < 3) { q = i18n("&Leave total amount of transaction at %1.", transactionSum); } else { q = i18n("&Leave %1 unassigned.", diff); } d->ui->leaveBtn->setText(q); } diff --git a/kmymoney/dialogs/splitadjustdialog.h b/kmymoney/dialogs/splitadjustdialog.h index e097a9167..7916b85d9 100644 --- a/kmymoney/dialogs/splitadjustdialog.h +++ b/kmymoney/dialogs/splitadjustdialog.h @@ -1,50 +1,51 @@ /*************************************************************************** splitadjustdialog.h ------------------- begin : Sat Jul 23 2016 copyright : (C) 2016 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef SPLITADJUSTDIALOG_H #define SPLITADJUSTDIALOG_H // ---------------------------------------------------------------------------- // QT Includes #include #include class SplitAdjustDialog : public QDialog { Q_OBJECT public: explicit SplitAdjustDialog(QWidget* parent, Qt::WindowFlags f = 0); virtual ~SplitAdjustDialog(); void setValues(QString transactionSum, QString splitSum, QString diff, int splitCount); enum Options { SplitAdjustContinue, SplitAdjustChange, SplitAdjustDistribute, SplitAdjustLeaveAsIs }; Options selectedOption() const; private: class Private; QScopedPointer d; }; -#endif // SPLITADJUSTDIALOG_H \ No newline at end of file +#endif // SPLITADJUSTDIALOG_H diff --git a/kmymoney/dialogs/transactioneditor.cpp b/kmymoney/dialogs/stdtransactioneditor.cpp similarity index 50% copy from kmymoney/dialogs/transactioneditor.cpp copy to kmymoney/dialogs/stdtransactioneditor.cpp index 2b37f0a55..eb25b4d4e 100644 --- a/kmymoney/dialogs/transactioneditor.cpp +++ b/kmymoney/dialogs/stdtransactioneditor.cpp @@ -1,2297 +1,1614 @@ /*************************************************************************** - transactioneditor.cpp + stdtransactioneditor.cpp ---------- begin : Wed Jun 07 2006 copyright : (C) 2006 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ -#include "transactioneditor.h" +#include "stdtransactioneditor.h" +#include "transactioneditor_p.h" // ---------------------------------------------------------------------------- // QT Includes #include #include -#include -#include -#include #include -#include -#include #include -#include // ---------------------------------------------------------------------------- // KDE Includes #include #include -#include #include #include -#include // ---------------------------------------------------------------------------- // Project Includes -#include "mymoneyutils.h" #include "kmymoneycategory.h" #include "kmymoneymvccombo.h" #include "kmymoneydateinput.h" #include "kmymoneyedit.h" #include "kmymoneylineedit.h" -#include #include "kmymoneyaccountselector.h" #include "mymoneyfile.h" -#include "mymoneyprice.h" -#include "mymoneysecurity.h" #include "mymoneypayee.h" #include "mymoneytag.h" -#include "mymoneyschedule.h" #include "kmymoneyutils.h" +#include "kmymoneycompletion.h" #include "transactionform.h" #include "kmymoneyglobalsettings.h" #include "transactioneditorcontainer.h" #include "ksplittransactiondlg.h" #include "kcurrencycalculator.h" #include "kselecttransactionsdlg.h" -#include "icons.h" using namespace KMyMoneyRegister; using namespace KMyMoneyTransactionForm; -using namespace Icons; - -TransactionEditor::TransactionEditor() : - m_paymentMethod(eMyMoney::Schedule::PaymentType::Any), - m_regForm(0), - m_item(0), - m_initialAction(ActionNone), - m_openEditSplits(false), - m_memoChanged(false) -{ -} - -TransactionEditor::TransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::Transaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate) : - m_paymentMethod(eMyMoney::Schedule::PaymentType::Any), - m_transactions(list), - m_regForm(regForm), - m_item(item), - m_transaction(item->transaction()), - m_split(item->split()), - m_lastPostDate(lastPostDate), - m_initialAction(ActionNone), - m_openEditSplits(false), - m_memoChanged(false) -{ - m_item->startEditMode(); - connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotUpdateAccount())); -} - -TransactionEditor::~TransactionEditor() -{ - // Make sure the widgets do not send out signals to the editor anymore - // After all, the editor is about to die - - //disconnect first tagCombo: - KTagContainer *w = dynamic_cast(haveWidget("tag")); - if (w && w->tagCombo()) { - w->tagCombo()->disconnect(this); - } - - QMap::iterator it_w; - for (it_w = m_editWidgets.begin(); it_w != m_editWidgets.end(); ++it_w) { - (*it_w)->disconnect(this); - } - - m_regForm->removeEditWidgets(m_editWidgets); - m_item->leaveEditMode(); - emit finishEdit(m_transactions); -} - -void TransactionEditor::slotUpdateAccount(const QString& id) -{ - m_account = MyMoneyFile::instance()->account(id); - setupPrecision(); -} - -void TransactionEditor::slotUpdateAccount() -{ - // reload m_account as it might have been changed - m_account = MyMoneyFile::instance()->account(m_account.id()); - setupPrecision(); -} - -void TransactionEditor::setupPrecision() -{ - const int prec = (m_account.id().isEmpty()) ? 2 : MyMoneyMoney::denomToPrec(m_account.fraction()); - QStringList widgets = QString("amount,deposit,payment").split(','); - QStringList::const_iterator it_w; - for (it_w = widgets.constBegin(); it_w != widgets.constEnd(); ++it_w) { - QWidget * w; - if ((w = haveWidget(*it_w)) != 0) { - dynamic_cast(w)->setPrecision(prec); - } - } -} - -void TransactionEditor::setup(QWidgetList& tabOrderWidgets, const MyMoneyAccount& account, KMyMoneyRegister::Action action) -{ - m_account = account; - m_initialAction = action; - createEditWidgets(); - m_regForm->arrangeEditWidgets(m_editWidgets, m_item); - m_regForm->tabOrder(tabOrderWidgets, m_item); - QWidget* w = haveWidget("tabbar"); - if (w) { - tabOrderWidgets.append(w); - TabBar* tabbar = dynamic_cast(w); - if ((tabbar) && (action == KMyMoneyRegister::ActionNone)) { - action = static_cast(tabbar->currentIndex()); - } - } - loadEditWidgets(action); - - // remove all unused widgets and don't forget to remove them - // from the tab order list as well - m_editWidgets.removeOrphans(); - QWidgetList::iterator it_w; - const QWidgetList editWidgets(m_editWidgets.values()); - for (it_w = tabOrderWidgets.begin(); it_w != tabOrderWidgets.end();) { - if (editWidgets.contains(*it_w)) { - ++it_w; - } else { - // before we remove the widget, we make sure it's not a part of a known one. - // these could be a direct child in case of KMyMoneyDateInput and KMyMoneyEdit - // where we store the pointer to the surrounding frame in editWidgets - // or the parent is called "KMyMoneyCategoryFrame" - if (*it_w) { - if (editWidgets.contains((*it_w)->parentWidget()) - || ((*it_w)->parentWidget() && (*it_w)->parentWidget()->objectName() == QLatin1String("KMyMoneyCategoryFrame"))) { - ++it_w; - - } else { - // qDebug("Remove '%s' from taborder", qPrintable((*it_w)->objectName())); - it_w = tabOrderWidgets.erase(it_w); - } - } else { - it_w = tabOrderWidgets.erase(it_w); - } - } - } - - clearFinalWidgets(); - setupFinalWidgets(); - slotUpdateButtonState(); -} - -void TransactionEditor::clearFinalWidgets() -{ - m_finalEditWidgets.clear(); -} - -void TransactionEditor::addFinalWidget(const QWidget* w) -{ - if (w) { - m_finalEditWidgets << w; - } -} -void TransactionEditor::slotReloadEditWidgets() +class StdTransactionEditorPrivate : public TransactionEditorPrivate { -} - -bool TransactionEditor::eventFilter(QObject* o, QEvent* e) -{ - bool rc = false; - if (o == haveWidget("number")) { - if (e->type() == QEvent::MouseButtonDblClick) { - emit assignNumber(); - rc = true; - } - } - - // if the object is a widget, the event is a key press event and - // the object is one of our edit widgets, then .... - if (o->isWidgetType() - && (e->type() == QEvent::KeyPress) - && m_editWidgets.values().contains(dynamic_cast(o))) { - QKeyEvent* k = dynamic_cast(e); - if ((k->modifiers() & Qt::KeyboardModifierMask) == 0 - || (k->modifiers() & Qt::KeypadModifier) != 0) { - bool isFinal = false; - QList::const_iterator it_w; - switch (k->key()) { - case Qt::Key_Return: - case Qt::Key_Enter: - // we check, if the object is one of the m_finalEditWidgets and if it's - // a kMyMoneyEdit object that the value is not 0. If any of that is the - // case, it's the final object. In other cases, we convert the enter - // key into a TAB key to move between the fields. Of course, we only need - // to do this as long as the appropriate option is set. In all other cases, - // we treat the return/enter key as such. - if (KMyMoneyGlobalSettings::enterMovesBetweenFields()) { - for (it_w = m_finalEditWidgets.constBegin(); !isFinal && it_w != m_finalEditWidgets.constEnd(); ++it_w) { - if (*it_w == o) { - if (dynamic_cast(*it_w)) { - isFinal = !(dynamic_cast(*it_w)->value().isZero()); - } else - isFinal = true; - } - } - } else - isFinal = true; - - // for the non-final objects, we treat the return key as a TAB - if (!isFinal) { - QKeyEvent evt(e->type(), - Qt::Key_Tab, k->modifiers(), QString(), - k->isAutoRepeat(), k->count()); - - QApplication::sendEvent(o, &evt); - // in case of a category item and the split button is visible - // send a second event so that we get passed the button. - if (dynamic_cast(o) && dynamic_cast(o)->splitButton()) - QApplication::sendEvent(o, &evt); - - } else { - QTimer::singleShot(0, this, SIGNAL(returnPressed())); - } - // don't process any further - rc = true; - break; - - case Qt::Key_Escape: - QTimer::singleShot(0, this, SIGNAL(escapePressed())); - break; - } - } - } - return rc; -} - -void TransactionEditor::slotNumberChanged(const QString& txt) -{ - QString next = txt; - kMyMoneyLineEdit* number = dynamic_cast(haveWidget("number")); - QString schedInfo; - if (!m_scheduleInfo.isEmpty()) { - schedInfo = i18n("
Processing schedule for %1.
", m_scheduleInfo); - } - - while (MyMoneyFile::instance()->checkNoUsed(m_account.id(), next)) { - if (KMessageBox::questionYesNo(m_regForm, QString("") + schedInfo + i18n("
Check number %1 has already been used in account %2.
" - "
Do you want to replace it with the next available number?
", next, m_account.name()) + QString("
"), i18n("Duplicate number")) == KMessageBox::Yes) { - assignNextNumber(); - next = KMyMoneyUtils::nextCheckNumber(m_account); - } else { - number->setText(QString()); - break; - } - } -} - -void TransactionEditor::slotUpdateMemoState() -{ - KTextEdit* memo = dynamic_cast(m_editWidgets["memo"]); - if (memo) { - m_memoChanged = (memo->toPlainText() != m_memoText); - } -} - -void TransactionEditor::slotUpdateButtonState() -{ - QString reason; - emit transactionDataSufficient(isComplete(reason)); -} - -QWidget* TransactionEditor::haveWidget(const QString& name) const -{ - return m_editWidgets.haveWidget(name); -} - -int TransactionEditor::slotEditSplits() -{ - return QDialog::Rejected; -} - -void TransactionEditor::setTransaction(const MyMoneyTransaction& t, const MyMoneySplit& s) -{ - m_transaction = t; - m_split = s; - loadEditWidgets(); -} - -bool TransactionEditor::fixTransactionCommodity(const MyMoneyAccount& account) -{ - bool rc = true; - bool firstTimeMultiCurrency = true; - m_account = account; - - MyMoneyFile* file = MyMoneyFile::instance(); - - // determine the max fraction for this account - MyMoneySecurity sec = file->security(m_account.currencyId()); - int fract = m_account.fraction(); - - // scan the list of selected transactions - KMyMoneyRegister::SelectedTransactions::iterator it_t; - for (it_t = m_transactions.begin(); (rc == true) && (it_t != m_transactions.end()); ++it_t) { - // there was a time when the schedule editor did not setup the transaction commodity - // let's give a helping hand here for those old schedules - if ((*it_t).transaction().commodity().isEmpty()) - (*it_t).transaction().setCommodity(m_account.currencyId()); - // we need to check things only if a different commodity is used - if (m_account.currencyId() != (*it_t).transaction().commodity()) { - MyMoneySecurity osec = file->security((*it_t).transaction().commodity()); - switch ((*it_t).transaction().splitCount()) { - case 0: - // new transaction, guess nothing's here yet ;) - break; - - case 1: - try { - // make sure, that the value is equal to the shares, don't forget our own copy - MyMoneySplit& splitB = (*it_t).split(); // reference usage wanted here - if (m_split == splitB) - m_split.setValue(splitB.shares()); - splitB.setValue(splitB.shares()); - (*it_t).transaction().modifySplit(splitB); - - } catch (const MyMoneyException &e) { - qDebug("Unable to update commodity to second splits currency in %s: '%s'", qPrintable((*it_t).transaction().id()), qPrintable(e.what())); - } - break; - - case 2: - // If we deal with multiple currencies we make sure, that for - // transactions with two splits, the transaction's commodity is the - // currency of the currently selected account. This saves us from a - // lot of grieve later on. We just have to switch the - // transactions commodity. Let's assume the following scenario: - // - transactions commodity is CA - // - splitB and account's currencyId is CB - // - splitA is of course in CA (otherwise we have a real problem) - // - Value is V in both splits - // - Shares in splitB is SB - // - Shares in splitA is SA (and equal to V) - // - // We do the following: - // - change transactions commodity to CB - // - set V in both splits to SB - // - modify the splits in the transaction - try { - // retrieve the splits - MyMoneySplit& splitB = (*it_t).split(); // reference usage wanted here - MyMoneySplit splitA = (*it_t).transaction().splitByAccount(m_account.id(), false); - - // - set V in both splits to SB. Don't forget our own copy - if (m_split == splitB) { - m_split.setValue(splitB.shares()); - } - splitB.setValue(splitB.shares()); - splitA.setValue(-splitB.shares()); - (*it_t).transaction().modifySplit(splitA); - (*it_t).transaction().modifySplit(splitB); - - } catch (const MyMoneyException &e) { - qDebug("Unable to update commodity to second splits currency in %s: '%s'", qPrintable((*it_t).transaction().id()), qPrintable(e.what())); - } - break; - - default: - // TODO: use new logic by adjusting all splits by the price - // extracted from the selected split. Inform the user that - // this will happen and allow him to stop the processing (rc = false) - - try { - QString msg; - if (firstTimeMultiCurrency) { - firstTimeMultiCurrency = false; - if (!isMultiSelection()) { - msg = i18n("This transaction has more than two splits and is originally based on a different currency (%1). Using this account to modify the transaction may result in rounding errors. Do you want to continue?", osec.name()); - } else { - msg = i18n("At least one of the selected transactions has more than two splits and is originally based on a different currency (%1). Using this account to modify the transactions may result in rounding errors. Do you want to continue?", osec.name()); - } - - if (KMessageBox::warningContinueCancel(0, QString("%1").arg(msg)) == KMessageBox::Cancel) { - rc = false; - } - } - - if (rc == true) { - MyMoneyMoney price; - if (!(*it_t).split().shares().isZero() && !(*it_t).split().value().isZero()) - price = (*it_t).split().shares() / (*it_t).split().value(); - QList::iterator it_s; - MyMoneySplit& mySplit = (*it_t).split(); - for (it_s = (*it_t).transaction().splits().begin(); it_s != (*it_t).transaction().splits().end(); ++it_s) { - MyMoneySplit s = (*it_s); - if (s == mySplit) { - s.setValue(s.shares()); - if (mySplit == m_split) { - m_split = s; - } - mySplit = s; - } else { - s.setValue((s.value() * price).convert(fract)); - } - (*it_t).transaction().modifySplit(s); - } - } - } catch (const MyMoneyException &e) { - qDebug("Unable to update commodity of split currency in %s: '%s'", qPrintable((*it_t).transaction().id()), qPrintable(e.what())); - } - break; - } - - // set the transaction's ommodity to this account's currency - (*it_t).transaction().setCommodity(m_account.currencyId()); - - // update our copy of the transaction that has the focus - if ((*it_t).transaction().id() == m_transaction.id()) { - m_transaction = (*it_t).transaction(); - } - } - } - return rc; -} - -void TransactionEditor::assignNextNumber() -{ - if (canAssignNumber()) { - kMyMoneyLineEdit* number = dynamic_cast(haveWidget("number")); - QString num = KMyMoneyUtils::nextCheckNumber(m_account); - bool showMessage = true; - int rc = KMessageBox::No; - QString schedInfo; - if (!m_scheduleInfo.isEmpty()) { - schedInfo = i18n("
Processing schedule for %1.
", m_scheduleInfo); - } - while (MyMoneyFile::instance()->checkNoUsed(m_account.id(), num)) { - if (showMessage) { - rc = KMessageBox::questionYesNo(m_regForm, QString("") + schedInfo + i18n("Check number %1 has already been used in account %2." - "
Do you want to replace it with the next available number?
", num, m_account.name()) + QString("
"), i18n("Duplicate number")); - showMessage = false; - } - if (rc == KMessageBox::Yes) { - num = KMyMoneyUtils::nextCheckNumber(m_account); - KMyMoneyUtils::updateLastNumberUsed(m_account, num); - m_account.setValue("lastNumberUsed", num); - number->loadText(num); - } else { - num = QString(); - break; - } - } - number->setText(num); - } -} - -bool TransactionEditor::canAssignNumber() const -{ - kMyMoneyLineEdit* number = dynamic_cast(haveWidget("number")); - return (number != 0); -} - -void TransactionEditor::setupCategoryWidget(KMyMoneyCategory* category, const QList& splits, QString& categoryId, const char* splitEditSlot, bool /* allowObjectCreation */) -{ - disconnect(category, SIGNAL(focusIn()), this, splitEditSlot); -#if 0 - // FIXME must deal with the logic that suppressObjectCreation is - // automatically turned off when the createItem() signal is connected - if (allowObjectCreation) - category->setSuppressObjectCreation(false); -#endif - - switch (splits.count()) { - case 0: - categoryId.clear(); - if (!category->currentText().isEmpty()) { - // category->clearEditText(); // don't clear as could be from another widget - Bug 322768 - // make sure, we don't see the selector - category->completion()->hide(); - } - category->completion()->setSelected(QString()); - break; - - case 1: - categoryId = splits[0].accountId(); - category->completion()->setSelected(categoryId); - category->slotItemSelected(categoryId); - break; - - default: - categoryId.clear(); - category->setSplitTransaction(); - connect(category, SIGNAL(focusIn()), this, splitEditSlot); -#if 0 - // FIXME must deal with the logic that suppressObjectCreation is - // automatically turned off when the createItem() signal is connected - if (allowObjectCreation) - category->setSuppressObjectCreation(true); -#endif - break; - } -} - -bool TransactionEditor::enterTransactions(QString& newId, bool askForSchedule, bool suppressBalanceWarnings) -{ - newId.clear(); - MyMoneyFile* file = MyMoneyFile::instance(); - - // make sure to run through all stuff that is tied to 'focusout events'. - m_regForm->parentWidget()->setFocus(); - QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 10); - // we don't need to update our widgets anymore, so we just disconnect the signal - disconnect(file, SIGNAL(dataChanged()), this, SLOT(slotReloadEditWidgets())); - - KMyMoneyRegister::SelectedTransactions::iterator it_t; - MyMoneyTransaction t; - bool newTransactionCreated = false; - - // make sure, that only a single new transaction can be created. - // we need to update m_transactions to contain the new transaction - // which is then stored in the variable t when we leave the loop. - // m_transactions will be sent out in finishEdit() and forces - // the new transaction to be selected in the ledger view - - // collect the transactions to be stored in the engine in a local - // list first, so that the user has a chance to interrupt the storage - // process - QList list; - bool storeTransactions = true; - - // collect transactions - for (it_t = m_transactions.begin(); storeTransactions && !newTransactionCreated && it_t != m_transactions.end(); ++it_t) { - storeTransactions = createTransaction(t, (*it_t).transaction(), (*it_t).split()); - // if the transaction was created successfully, append it to the list - if (storeTransactions) - list.append(t); - - // if we created a new transaction keep that in mind - if (t.id().isEmpty()) - newTransactionCreated = true; - } - - // if not interrupted by user, continue to store them in the engine - if (storeTransactions) { - int i = 0; - emit statusMsg(i18n("Storing transactions")); - emit statusProgress(0, list.count()); - - MyMoneyFileTransaction ft; - - try { - QList::iterator it_ts; - QMap minBalanceEarly; - QMap minBalanceAbsolute; - QMap maxCreditEarly; - QMap maxCreditAbsolute; - QMap accountIds; - - for (it_ts = list.begin(); it_ts != list.end(); ++it_ts) { - // if we have a categorization, make sure we remove - // the 'imported' flag automagically - if ((*it_ts).splitCount() > 1) - (*it_ts).setImported(false); - - // create information about min and max balances - QList::const_iterator it_s; - for (it_s = (*it_ts).splits().constBegin(); it_s != (*it_ts).splits().constEnd(); ++it_s) { - MyMoneyAccount acc = file->account((*it_s).accountId()); - accountIds[acc.id()] = true; - MyMoneyMoney balance = file->balance(acc.id()); - if (!acc.value("minBalanceEarly").isEmpty()) { - minBalanceEarly[acc.id()] = balance < MyMoneyMoney(acc.value("minBalanceEarly")); - } - if (!acc.value("minBalanceAbsolute").isEmpty()) { - minBalanceAbsolute[acc.id()] = balance < MyMoneyMoney(acc.value("minBalanceAbsolute")); - minBalanceEarly[acc.id()] = false; - } - if (!acc.value("maxCreditEarly").isEmpty()) { - maxCreditEarly[acc.id()] = balance < MyMoneyMoney(acc.value("maxCreditEarly")); - } - if (!acc.value("maxCreditAbsolute").isEmpty()) { - maxCreditAbsolute[acc.id()] = balance < MyMoneyMoney(acc.value("maxCreditAbsolute")); - maxCreditEarly[acc.id()] = false; - } - } - - if ((*it_ts).id().isEmpty()) { - bool enter = true; - if (askForSchedule && (*it_ts).postDate() > QDate::currentDate()) { - KGuiItem enterButton(i18n("&Enter"), - QIcon::fromTheme(g_Icons[Icon::DialogOK]), - i18n("Accepts the entered data and stores it"), - i18n("Use this to enter the transaction into the ledger.")); - KGuiItem scheduleButton(i18n("&Schedule"), - QIcon::fromTheme(g_Icons[Icon::AppointmentNew]), - i18n("Accepts the entered data and stores it as schedule"), - i18n("Use this to schedule the transaction for later entry into the ledger.")); - - enter = KMessageBox::questionYesNo(m_regForm, QString("%1").arg(i18n("The transaction you are about to enter has a post date in the future.

Do you want to enter it in the ledger or add it to the schedules?")), i18nc("Dialog caption for 'Enter or schedule' dialog", "Enter or schedule?"), enterButton, scheduleButton, "EnterOrScheduleTransactionInFuture") == KMessageBox::Yes; - } - if (enter) { - // add new transaction - file->addTransaction(*it_ts); - // pass the newly assigned id on to the caller - newId = (*it_ts).id(); - // refresh account object for transactional changes - // refresh account and transaction object because they might have changed - m_account = file->account(m_account.id()); - t = (*it_ts); - - // if a new transaction has a valid number, keep it with the account - keepNewNumber((*it_ts)); - } else { - // turn object creation on, so that moving the focus does - // not screw up the dialog that might be popping up - emit objectCreation(true); - emit scheduleTransaction(*it_ts, eMyMoney::Schedule::Occurrence::Once); - emit objectCreation(false); - - newTransactionCreated = false; - } - - // send out the post date of this transaction - emit lastPostDateUsed((*it_ts).postDate()); - } else { - // modify existing transaction - // its number might have been edited - // bearing in mind it could contain alpha characters - keepNewNumber((*it_ts)); - file->modifyTransaction(*it_ts); - } - } - emit statusProgress(i++, 0); - - // update m_transactions to contain the newly created transaction so that - // it is selected as the current one - // we need to do that before we commit the transaction to the engine - // as we need it during the update of the views that is caused by committing already. - if (newTransactionCreated) { - m_transactions.clear(); - MyMoneySplit s; - // a transaction w/o a single split should not exist and adding it - // should throw an exception in MyMoneyFile::addTransaction, but we - // remain on the save side of things to check for it - if (t.splitCount() > 0) - s = t.splits().front(); - KMyMoneyRegister::SelectedTransaction st(t, s); - m_transactions.append(st); - } - - // Save pricing information - QList::const_iterator it_t; - for (it_t = t.splits().constBegin(); it_t != t.splits().constEnd(); ++it_t) { - if (((*it_t).action() != "Buy") && - ((*it_t).action() != "Reinvest")) { - continue; - } - QString id = (*it_t).accountId(); - MyMoneyAccount acc = file->account(id); - MyMoneySecurity sec = file->security(acc.currencyId()); - MyMoneyPrice price(acc.currencyId(), - sec.tradingCurrency(), - t.postDate(), - (*it_t).price(), "Transaction"); - file->addPrice(price); - break; - } - - ft.commit(); - - // now analyze the balances and spit out warnings to the user - QMap::const_iterator it_a; - - if (!suppressBalanceWarnings) { - for (it_a = accountIds.constBegin(); it_a != accountIds.constEnd(); ++it_a) { - QString msg; - MyMoneyAccount acc = file->account(it_a.key()); - MyMoneyMoney balance = file->balance(acc.id()); - const MyMoneySecurity& sec = file->security(acc.currencyId()); - QString key; - key = "minBalanceEarly"; - if (!acc.value(key).isEmpty()) { - if (minBalanceEarly[acc.id()] == false && balance < MyMoneyMoney(acc.value(key))) { - msg = QString("%1").arg(i18n("The balance of account %1 dropped below the warning balance of %2.", acc.name(), MyMoneyUtils::formatMoney(MyMoneyMoney(acc.value(key)), acc, sec))); - } - } - key = "minBalanceAbsolute"; - if (!acc.value(key).isEmpty()) { - if (minBalanceAbsolute[acc.id()] == false && balance < MyMoneyMoney(acc.value(key))) { - msg = QString("%1").arg(i18n("The balance of account %1 dropped below the minimum balance of %2.", acc.name(), MyMoneyUtils::formatMoney(MyMoneyMoney(acc.value(key)), acc, sec))); - } - } - key = "maxCreditEarly"; - if (!acc.value(key).isEmpty()) { - if (maxCreditEarly[acc.id()] == false && balance < MyMoneyMoney(acc.value(key))) { - msg = QString("%1").arg(i18n("The balance of account %1 dropped below the maximum credit warning limit of %2.", acc.name(), MyMoneyUtils::formatMoney(MyMoneyMoney(acc.value(key)), acc, sec))); - } - } - key = "maxCreditAbsolute"; - if (!acc.value(key).isEmpty()) { - if (maxCreditAbsolute[acc.id()] == false && balance < MyMoneyMoney(acc.value(key))) { - msg = QString("%1").arg(i18n("The balance of account %1 dropped below the maximum credit limit of %2.", acc.name(), MyMoneyUtils::formatMoney(MyMoneyMoney(acc.value(key)), acc, sec))); - } - } - - if (!msg.isEmpty()) { - emit balanceWarning(m_regForm, acc, msg); - } - } - } - } catch (const MyMoneyException &e) { - qDebug("Unable to store transaction within engine: %s", qPrintable(e.what())); - newTransactionCreated = false; - } - - emit statusProgress(-1, -1); - emit statusMsg(QString()); + Q_DISABLE_COPY(StdTransactionEditorPrivate) +public: + StdTransactionEditorPrivate(StdTransactionEditor *qq) : + TransactionEditorPrivate(qq), + m_inUpdateVat(false) + { } - return storeTransactions; -} -void TransactionEditor::keepNewNumber(const MyMoneyTransaction& tr) -{ - // verify that new number, possibly containing alpha, is valid - MyMoneyTransaction txn = tr; - MyMoneyFile* file = MyMoneyFile::instance(); - if (!txn.splits().isEmpty()) { - QString number = txn.splits().first().number(); - if (KMyMoneyUtils::numericPart(number) > 0) { - // numeric is valid - kMyMoneyLineEdit* numberEdit = dynamic_cast(haveWidget("number")); - if (numberEdit) { - numberEdit->loadText(number); - MyMoneySplit split = txn.splits().first(); - split.setNumber(number); - txn.modifySplit(split); - m_account.setValue("lastNumberUsed", number); - file->modifyAccount(m_account); - } - } + ~StdTransactionEditorPrivate() + { } -} -void TransactionEditor::resizeForm() -{ - // force resizeing of the columns in the form - KMyMoneyTransactionForm::TransactionForm* form = dynamic_cast(m_regForm); - if (form) { - QMetaObject::invokeMethod(form, "resize", Qt::QueuedConnection, QGenericReturnArgument(), Q_ARG(int, ValueColumn1)); - } -} + MyMoneyMoney m_shares; + bool m_inUpdateVat; +}; StdTransactionEditor::StdTransactionEditor() : - m_inUpdateVat(false) + TransactionEditor(*new StdTransactionEditorPrivate(this)) { } -StdTransactionEditor::StdTransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::Transaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate) : - TransactionEditor(regForm, item, list, lastPostDate), - m_inUpdateVat(false) +StdTransactionEditor::StdTransactionEditor(TransactionEditorContainer* regForm, + KMyMoneyRegister::Transaction* item, + const KMyMoneyRegister::SelectedTransactions& list, + const QDate& lastPostDate) : + TransactionEditor(*new StdTransactionEditorPrivate(this), + regForm, + item, + list, + lastPostDate) { } StdTransactionEditor::~StdTransactionEditor() { } - void StdTransactionEditor::createEditWidgets() { + Q_D(StdTransactionEditor); // we only create the account widget in case it is needed // to avoid confusion in the tab order later on. - if (m_item->showRowInForm(0)) { - KMyMoneyCategory* account = new KMyMoneyCategory; + if (d->m_item->showRowInForm(0)) { + auto account = new KMyMoneyCategory; account->setPlaceholderText(i18n("Account")); account->setObjectName(QLatin1String("Account")); - m_editWidgets["account"] = account; - connect(account, SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(account, SIGNAL(itemSelected(QString)), this, SLOT(slotUpdateAccount(QString))); + d->m_editWidgets["account"] = account; + connect(account, &QComboBox::editTextChanged, this, &StdTransactionEditor::slotUpdateButtonState); + connect(account, &KMyMoneyCombo::itemSelected, this, &StdTransactionEditor::slotUpdateAccount); } - KMyMoneyPayeeCombo* payee = new KMyMoneyPayeeCombo; + auto payee = new KMyMoneyPayeeCombo; payee->setPlaceholderText(i18n("Payer/Receiver")); payee->setObjectName(QLatin1String("Payee")); - m_editWidgets["payee"] = payee; + d->m_editWidgets["payee"] = payee; - connect(payee, SIGNAL(createItem(QString,QString&)), this, SIGNAL(createPayee(QString,QString&))); - connect(payee, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); - connect(payee, SIGNAL(itemSelected(QString)), this, SLOT(slotUpdatePayee(QString))); - connect(payee, SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateButtonState())); + connect(payee, &KMyMoneyMVCCombo::createItem, this, &TransactionEditor::createPayee); + connect(payee, &KMyMoneyMVCCombo::objectCreation, this, &TransactionEditor::objectCreation); + connect(payee, &KMyMoneyMVCCombo::itemSelected, this, &StdTransactionEditor::slotUpdatePayee); + connect(payee, &QComboBox::editTextChanged, this, &StdTransactionEditor::slotUpdateButtonState); - KMyMoneyCategory* category = new KMyMoneyCategory(0, true); + auto category = new KMyMoneyCategory(0, true); category->setPlaceholderText(i18n("Category/Account")); category->setObjectName(QLatin1String("Category/Account")); - m_editWidgets["category"] = category; - connect(category, SIGNAL(itemSelected(QString)), this, SLOT(slotUpdateCategory(QString))); - connect(category, SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(category, SIGNAL(createItem(QString,QString&)), this, SLOT(slotCreateCategory(QString,QString&))); - connect(category, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); - connect(category->splitButton(), SIGNAL(clicked()), this, SLOT(slotEditSplits())); + d->m_editWidgets["category"] = category; + connect(category, &KMyMoneyCombo::itemSelected, this, &StdTransactionEditor::slotUpdateCategory); + connect(category, &QComboBox::editTextChanged, this, &StdTransactionEditor::slotUpdateButtonState); + connect(category, &KMyMoneyCombo::createItem, this, &StdTransactionEditor::slotCreateCategory); + connect(category, &KMyMoneyCombo::objectCreation, this, &TransactionEditor::objectCreation); + connect(category->splitButton(), &QAbstractButton::clicked, this, &StdTransactionEditor::slotEditSplits); // initially disable the split button since we don't have an account set if (category->splitButton()) - category->splitButton()->setDisabled(m_account.id().isEmpty()); + category->splitButton()->setDisabled(d->m_account.id().isEmpty()); - KTagContainer* tag = new KTagContainer; + auto tag = new KTagContainer; tag->tagCombo()->setPlaceholderText(i18n("Tag")); tag->tagCombo()->setObjectName(QLatin1String("Tag")); - m_editWidgets["tag"] = tag; - connect(tag->tagCombo(), SIGNAL(createItem(QString,QString&)), this, SIGNAL(createTag(QString,QString&))); - connect(tag->tagCombo(), SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); + d->m_editWidgets["tag"] = tag; + connect(tag->tagCombo(), &KMyMoneyMVCCombo::createItem, this, &TransactionEditor::createTag); + connect(tag->tagCombo(), &KMyMoneyMVCCombo::objectCreation, this, &TransactionEditor::objectCreation); - KTextEdit* memo = new KTextEdit; + auto memo = new KTextEdit; memo->setObjectName(QLatin1String("Memo")); memo->setTabChangesFocus(true); - connect(memo, SIGNAL(textChanged()), this, SLOT(slotUpdateMemoState())); - connect(memo, SIGNAL(textChanged()), this, SLOT(slotUpdateButtonState())); - m_editWidgets["memo"] = memo; - m_memoText.clear(); - m_memoChanged = false; + connect(memo, &QTextEdit::textChanged, this, &StdTransactionEditor::slotUpdateMemoState); + connect(memo, &QTextEdit::textChanged, this, &StdTransactionEditor::slotUpdateButtonState); + d->m_editWidgets["memo"] = memo; + d->m_memoText.clear(); + d->m_memoChanged = false; bool showNumberField = true; - switch (m_account.accountType()) { + switch (d->m_account.accountType()) { case eMyMoney::Account::Savings: case eMyMoney::Account::Cash: case eMyMoney::Account::Loan: case eMyMoney::Account::AssetLoan: case eMyMoney::Account::Asset: case eMyMoney::Account::Liability: case eMyMoney::Account::Equity: showNumberField = KMyMoneyGlobalSettings::alwaysShowNrField(); break; case eMyMoney::Account::Income: case eMyMoney::Account::Expense: showNumberField = false; break; default: break; } if (showNumberField) { - kMyMoneyLineEdit* number = new kMyMoneyLineEdit; + auto number = new kMyMoneyLineEdit; number->setPlaceholderText(i18n("Number")); number->setObjectName(QLatin1String("Number")); - m_editWidgets["number"] = number; - connect(number, SIGNAL(lineChanged(QString)), this, SLOT(slotNumberChanged(QString))); + d->m_editWidgets["number"] = number; + connect(number, &kMyMoneyLineEdit::lineChanged, this, &StdTransactionEditor::slotNumberChanged); // number->installEventFilter(this); } - kMyMoneyDateInput* postDate = new kMyMoneyDateInput; - m_editWidgets["postdate"] = postDate; + auto postDate = new kMyMoneyDateInput; + d->m_editWidgets["postdate"] = postDate; postDate->setObjectName(QLatin1String("PostDate")); - connect(postDate, SIGNAL(dateChanged(QDate)), this, SLOT(slotUpdateButtonState())); + connect(postDate, &kMyMoneyDateInput::dateChanged, this, &StdTransactionEditor::slotUpdateButtonState); postDate->setDate(QDate()); - kMyMoneyEdit* value = new kMyMoneyEdit; - m_editWidgets["amount"] = value; + auto value = new kMyMoneyEdit; + d->m_editWidgets["amount"] = value; value->setObjectName(QLatin1String("Amount")); value->setResetButtonVisible(false); - connect(value, SIGNAL(valueChanged(QString)), this, SLOT(slotUpdateAmount(QString))); - connect(value, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateButtonState())); + connect(value, &kMyMoneyEdit::valueChanged, this, &StdTransactionEditor::slotUpdateAmount); + connect(value, &kMyMoneyEdit::textChanged, this, &StdTransactionEditor::slotUpdateButtonState); value = new kMyMoneyEdit; - m_editWidgets["payment"] = value; + d->m_editWidgets["payment"] = value; value->setObjectName(QLatin1String("Payment")); value->setResetButtonVisible(false); - connect(value, SIGNAL(valueChanged(QString)), this, SLOT(slotUpdatePayment(QString))); - connect(value, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateButtonState())); + connect(value, &kMyMoneyEdit::valueChanged, this, &StdTransactionEditor::slotUpdatePayment); + connect(value, &kMyMoneyEdit::textChanged, this, &StdTransactionEditor::slotUpdateButtonState); value = new kMyMoneyEdit; - m_editWidgets["deposit"] = value; + d->m_editWidgets["deposit"] = value; value->setObjectName(QLatin1String("Deposit")); value->setResetButtonVisible(false); - connect(value, SIGNAL(valueChanged(QString)), this, SLOT(slotUpdateDeposit(QString))); - connect(value, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateButtonState())); + connect(value, &kMyMoneyEdit::valueChanged, this, &StdTransactionEditor::slotUpdateDeposit); + connect(value, &kMyMoneyEdit::textChanged, this, &StdTransactionEditor::slotUpdateButtonState); - KMyMoneyCashFlowCombo* cashflow = new KMyMoneyCashFlowCombo(0, m_account.accountGroup()); - m_editWidgets["cashflow"] = cashflow; + auto cashflow = new KMyMoneyCashFlowCombo(0, d->m_account.accountGroup()); + d->m_editWidgets["cashflow"] = cashflow; cashflow->setObjectName(QLatin1String("Cashflow")); - connect(cashflow, SIGNAL(directionSelected(KMyMoneyRegister::CashFlowDirection)), this, SLOT(slotUpdateCashFlow(KMyMoneyRegister::CashFlowDirection))); + connect(cashflow, &KMyMoneyCashFlowCombo::directionSelected, this, &StdTransactionEditor::slotUpdateCashFlow); - KMyMoneyReconcileCombo* reconcile = new KMyMoneyReconcileCombo; - m_editWidgets["status"] = reconcile; + auto reconcile = new KMyMoneyReconcileCombo; + d->m_editWidgets["status"] = reconcile; reconcile->setObjectName(QLatin1String("Reconcile")); KMyMoneyRegister::QWidgetContainer::iterator it_w; - for (it_w = m_editWidgets.begin(); it_w != m_editWidgets.end(); ++it_w) { + for (it_w = d->m_editWidgets.begin(); it_w != d->m_editWidgets.end(); ++it_w) { (*it_w)->installEventFilter(this); } // if we don't have more than 1 selected transaction, we don't need // the "don't change" item in some of the combo widgets if (!isMultiSelection()) { reconcile->removeDontCare(); cashflow->removeDontCare(); } QLabel* label; - m_editWidgets["account-label"] = label = new QLabel(i18n("Account")); + d->m_editWidgets["account-label"] = label = new QLabel(i18n("Account")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["category-label"] = label = new QLabel(i18n("Category")); + d->m_editWidgets["category-label"] = label = new QLabel(i18n("Category")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["tag-label"] = label = new QLabel(i18n("Tags")); + d->m_editWidgets["tag-label"] = label = new QLabel(i18n("Tags")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["memo-label"] = label = new QLabel(i18n("Memo")); + d->m_editWidgets["memo-label"] = label = new QLabel(i18n("Memo")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["number-label"] = label = new QLabel(i18n("Number")); + d->m_editWidgets["number-label"] = label = new QLabel(i18n("Number")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["date-label"] = label = new QLabel(i18n("Date")); + d->m_editWidgets["date-label"] = label = new QLabel(i18n("Date")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["amount-label"] = label = new QLabel(i18n("Amount")); + d->m_editWidgets["amount-label"] = label = new QLabel(i18n("Amount")); label->setAlignment(Qt::AlignVCenter); - m_editWidgets["status-label"] = label = new QLabel(i18n("Status")); + d->m_editWidgets["status-label"] = label = new QLabel(i18n("Status")); label->setAlignment(Qt::AlignVCenter); // create a copy of tabbar above the form (if we are created for a form) - KMyMoneyTransactionForm::TransactionForm* form = dynamic_cast(m_regForm); + KMyMoneyTransactionForm::TransactionForm* form = dynamic_cast(d->m_regForm); if (form) { KMyMoneyTransactionForm::TabBar* tabbar = new KMyMoneyTransactionForm::TabBar; - m_editWidgets["tabbar"] = tabbar; + d->m_editWidgets["tabbar"] = tabbar; tabbar->setObjectName(QLatin1String("TabBar")); tabbar->copyTabs(form->tabBar()); - connect(tabbar, SIGNAL(tabCurrentChanged(int)), this, SLOT(slotUpdateAction(int))); - connect(tabbar, SIGNAL(tabCurrentChanged(int)), this, SIGNAL(operationTypeChanged(int))); + connect(tabbar, &TabBar::tabCurrentChanged, this, &StdTransactionEditor::slotUpdateAction); + connect(tabbar, &TabBar::tabCurrentChanged, this, &TransactionEditor::operationTypeChanged); } setupPrecision(); } void StdTransactionEditor::setupCategoryWidget(QString& categoryId) { - TransactionEditor::setupCategoryWidget(dynamic_cast(m_editWidgets["category"]), m_splits, categoryId, SLOT(slotEditSplits())); + Q_D(StdTransactionEditor); + TransactionEditor::setupCategoryWidget(dynamic_cast(d->m_editWidgets["category"]), d->m_splits, categoryId, SLOT(slotEditSplits())); - if (m_splits.count() == 1) - m_shares = m_splits[0].shares(); + if (d->m_splits.count() == 1) + d->m_shares = d->m_splits[0].shares(); } bool StdTransactionEditor::isTransfer(const QString& accId1, const QString& accId2) const { if (accId1.isEmpty() || accId2.isEmpty()) return false; return MyMoneyFile::instance()->account(accId1).isIncomeExpense() == MyMoneyFile::instance()->account(accId2).isIncomeExpense(); } void StdTransactionEditor::loadEditWidgets(KMyMoneyRegister::Action action) { + Q_D(StdTransactionEditor); // don't kick off VAT processing from here - m_inUpdateVat = true; + d->m_inUpdateVat = true; QMap::const_iterator it_w; QWidget* w; AccountSet aSet; // load the account widget KMyMoneyCategory* account = dynamic_cast(haveWidget("account")); if (account) { aSet.addAccountGroup(eMyMoney::Account::Asset); aSet.addAccountGroup(eMyMoney::Account::Liability); aSet.removeAccountType(eMyMoney::Account::AssetLoan); aSet.removeAccountType(eMyMoney::Account::CertificateDep); aSet.removeAccountType(eMyMoney::Account::Investment); aSet.removeAccountType(eMyMoney::Account::Stock); aSet.removeAccountType(eMyMoney::Account::MoneyMarket); aSet.removeAccountType(eMyMoney::Account::Loan); aSet.load(account->selector()); - account->completion()->setSelected(m_account.id()); - account->slotItemSelected(m_account.id()); + account->completion()->setSelected(d->m_account.id()); + account->slotItemSelected(d->m_account.id()); } // load the payee widget - KMyMoneyPayeeCombo* payee = dynamic_cast(m_editWidgets["payee"]); + auto payee = dynamic_cast(d->m_editWidgets["payee"]); payee->loadPayees(MyMoneyFile::instance()->payeeList()); // load the category widget - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); - disconnect(category, SIGNAL(focusIn()), this, SLOT(slotEditSplits())); + auto category = dynamic_cast(d->m_editWidgets["category"]); + disconnect(category, &KMyMoneyCategory::focusIn, this, &StdTransactionEditor::slotEditSplits); // load the tag widget - //KMyMoneyTagCombo* tag = dynamic_cast(m_editWidgets["tag"]); - KTagContainer* tag = dynamic_cast(m_editWidgets["tag"]); + //auto tag = dynamic_cast(m_editWidgets["tag"]); + auto tag = dynamic_cast(d->m_editWidgets["tag"]); tag->loadTags(MyMoneyFile::instance()->tagList()); // check if the current transaction has a reference to an equity account bool haveEquityAccount = false; QList::const_iterator it_s; - for (it_s = m_transaction.splits().constBegin(); !haveEquityAccount && it_s != m_transaction.splits().constEnd(); ++it_s) { + for (it_s = d->m_transaction.splits().constBegin(); !haveEquityAccount && it_s != d->m_transaction.splits().constEnd(); ++it_s) { MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId()); if (acc.accountType() == eMyMoney::Account::Equity) haveEquityAccount = true; } aSet.clear(); aSet.addAccountGroup(eMyMoney::Account::Asset); aSet.addAccountGroup(eMyMoney::Account::Liability); aSet.addAccountGroup(eMyMoney::Account::Income); aSet.addAccountGroup(eMyMoney::Account::Expense); if (KMyMoneyGlobalSettings::expertMode() || haveEquityAccount) aSet.addAccountGroup(eMyMoney::Account::Equity); aSet.removeAccountType(eMyMoney::Account::CertificateDep); aSet.removeAccountType(eMyMoney::Account::Investment); aSet.removeAccountType(eMyMoney::Account::Stock); aSet.removeAccountType(eMyMoney::Account::MoneyMarket); aSet.load(category->selector()); // if an account is specified then remove it from the widget so that the user // cannot create a transfer with from and to account being the same account - if (!m_account.id().isEmpty()) - category->selector()->removeItem(m_account.id()); + if (!d->m_account.id().isEmpty()) + category->selector()->removeItem(d->m_account.id()); // also show memo text if isMultiSelection() - dynamic_cast(m_editWidgets["memo"])->setText(m_split.memo()); + dynamic_cast(d->m_editWidgets["memo"])->setText(d->m_split.memo()); // need to know if it changed - m_memoText = m_split.memo(); - m_memoChanged = false; + d->m_memoText = d->m_split.memo(); + d->m_memoChanged = false; if (!isMultiSelection()) { - if (m_transaction.postDate().isValid()) - dynamic_cast(m_editWidgets["postdate"])->setDate(m_transaction.postDate()); - else if (m_lastPostDate.isValid()) - dynamic_cast(m_editWidgets["postdate"])->setDate(m_lastPostDate); + if (d->m_transaction.postDate().isValid()) + dynamic_cast(d->m_editWidgets["postdate"])->setDate(d->m_transaction.postDate()); + else if (d->m_lastPostDate.isValid()) + dynamic_cast(d->m_editWidgets["postdate"])->setDate(d->m_lastPostDate); else - dynamic_cast(m_editWidgets["postdate"])->setDate(QDate::currentDate()); + dynamic_cast(d->m_editWidgets["postdate"])->setDate(QDate::currentDate()); if ((w = haveWidget("number")) != 0) { - dynamic_cast(w)->loadText(m_split.number()); - if (m_transaction.id().isEmpty() // new transaction + dynamic_cast(w)->loadText(d->m_split.number()); + if (d->m_transaction.id().isEmpty() // new transaction && dynamic_cast(w)->text().isEmpty() // no number filled in - && m_account.accountType() == eMyMoney::Account::Checkings // checkings account + && d->m_account.accountType() == eMyMoney::Account::Checkings // checkings account && KMyMoneyGlobalSettings::autoIncCheckNumber() // and auto inc number turned on? && action != KMyMoneyRegister::ActionDeposit // only transfers or withdrawals - && m_paymentMethod == eMyMoney::Schedule::PaymentType::WriteChecque) {// only for WriteChecque + && d->m_paymentMethod == eMyMoney::Schedule::PaymentType::WriteChecque) {// only for WriteChecque assignNextNumber(); } } - dynamic_cast(m_editWidgets["status"])->setState(m_split.reconcileFlag()); + dynamic_cast(d->m_editWidgets["status"])->setState(d->m_split.reconcileFlag()); - QString payeeId = m_split.payeeId(); + QString payeeId = d->m_split.payeeId(); if (!payeeId.isEmpty()) { payee->setSelectedItem(payeeId); } - QList t = m_split.tagIdList(); + QList t = d->m_split.tagIdList(); if (!t.isEmpty()) { - for (int i = 0; i < t.size(); i++) + for (auto i = 0; i < t.size(); i++) tag->addTagWidget(t[i]); } - m_splits.clear(); - if (m_transaction.splitCount() < 2) { + d->m_splits.clear(); + if (d->m_transaction.splitCount() < 2) { category->completion()->setSelected(QString()); } else { QList::const_iterator it_s; - for (it_s = m_transaction.splits().constBegin(); it_s != m_transaction.splits().constEnd(); ++it_s) { - if ((*it_s) == m_split) + for (it_s = d->m_transaction.splits().constBegin(); it_s != d->m_transaction.splits().constEnd(); ++it_s) { + if ((*it_s) == d->m_split) continue; - m_splits.append(*it_s); + d->m_splits.append(*it_s); } } QString categoryId; setupCategoryWidget(categoryId); if ((w = haveWidget("cashflow")) != 0) { KMyMoneyCashFlowCombo* cashflow = dynamic_cast(w); - cashflow->setDirection(!m_split.value().isPositive() ? KMyMoneyRegister::Payment : KMyMoneyRegister::Deposit); // include isZero case + cashflow->setDirection(!d->m_split.value().isPositive() ? KMyMoneyRegister::Payment : KMyMoneyRegister::Deposit); // include isZero case } if ((w = haveWidget("category-label")) != 0) { QLabel *categoryLabel = dynamic_cast(w); - if (isTransfer(m_split.accountId(), categoryId)) { - if (m_split.value().isPositive()) + if (isTransfer(d->m_split.accountId(), categoryId)) { + if (d->m_split.value().isPositive()) categoryLabel->setText(i18n("Transfer from")); else categoryLabel->setText(i18n("Transfer to")); } } - MyMoneyMoney value = m_split.shares(); + MyMoneyMoney value = d->m_split.shares(); if (haveWidget("deposit")) { - if (m_split.shares().isNegative()) { - dynamic_cast(m_editWidgets["deposit"])->loadText(""); - dynamic_cast(m_editWidgets["payment"])->setValue(value.abs()); + if (d->m_split.shares().isNegative()) { + dynamic_cast(d->m_editWidgets["deposit"])->loadText(""); + dynamic_cast(d->m_editWidgets["payment"])->setValue(value.abs()); } else { - dynamic_cast(m_editWidgets["deposit"])->setValue(value.abs()); - dynamic_cast(m_editWidgets["payment"])->loadText(""); + dynamic_cast(d->m_editWidgets["deposit"])->setValue(value.abs()); + dynamic_cast(d->m_editWidgets["payment"])->loadText(""); } } if ((w = haveWidget("amount")) != 0) { dynamic_cast(w)->setValue(value.abs()); } slotUpdateCategory(categoryId); // try to preset for specific action if a new transaction is being started - if (m_transaction.id().isEmpty()) { + if (d->m_transaction.id().isEmpty()) { if ((w = haveWidget("category-label")) != 0) { TabBar* tabbar = dynamic_cast(haveWidget("tabbar")); if (action == KMyMoneyRegister::ActionNone) { if (tabbar) { action = static_cast(tabbar->currentIndex()); } } if (action != KMyMoneyRegister::ActionNone) { QLabel *categoryLabel = dynamic_cast(w); if (action == KMyMoneyRegister::ActionTransfer) { - if (m_split.value().isPositive()) + if (d->m_split.value().isPositive()) categoryLabel->setText(i18n("Transfer from")); else categoryLabel->setText(i18n("Transfer to")); } if ((w = haveWidget("cashflow")) != 0) { KMyMoneyCashFlowCombo* cashflow = dynamic_cast(w); - if (action == KMyMoneyRegister::ActionDeposit || (action == KMyMoneyRegister::ActionTransfer && m_split.value().isPositive())) + if (action == KMyMoneyRegister::ActionDeposit || (action == KMyMoneyRegister::ActionTransfer && d->m_split.value().isPositive())) cashflow->setDirection(KMyMoneyRegister::Deposit); else cashflow->setDirection(KMyMoneyRegister::Payment); } if (tabbar) { tabbar->setCurrentIndex(action); } } } } else { TabBar* tabbar = dynamic_cast(haveWidget("tabbar")); if (tabbar) { - if (!isTransfer(m_split.accountId(), categoryId)) { - tabbar->setCurrentIndex(m_split.value().isNegative() ? KMyMoneyRegister::ActionWithdrawal : KMyMoneyRegister::ActionDeposit); + if (!isTransfer(d->m_split.accountId(), categoryId)) { + tabbar->setCurrentIndex(d->m_split.value().isNegative() ? KMyMoneyRegister::ActionWithdrawal : KMyMoneyRegister::ActionDeposit); } else { tabbar->setCurrentIndex(KMyMoneyRegister::ActionTransfer); } } } } else { // isMultiSelection() - dynamic_cast(m_editWidgets["postdate"])->loadDate(QDate()); - dynamic_cast(m_editWidgets["status"])->setState(eMyMoney::Split::State::Unknown); + dynamic_cast(d->m_editWidgets["postdate"])->loadDate(QDate()); + dynamic_cast(d->m_editWidgets["status"])->setState(eMyMoney::Split::State::Unknown); if (haveWidget("deposit")) { - dynamic_cast(m_editWidgets["deposit"])->loadText(""); - dynamic_cast(m_editWidgets["deposit"])->setAllowEmpty(); - dynamic_cast(m_editWidgets["payment"])->loadText(""); - dynamic_cast(m_editWidgets["payment"])->setAllowEmpty(); + dynamic_cast(d->m_editWidgets["deposit"])->loadText(""); + dynamic_cast(d->m_editWidgets["deposit"])->setAllowEmpty(); + dynamic_cast(d->m_editWidgets["payment"])->loadText(""); + dynamic_cast(d->m_editWidgets["payment"])->setAllowEmpty(); } if ((w = haveWidget("amount")) != 0) { dynamic_cast(w)->loadText(""); dynamic_cast(w)->setAllowEmpty(); } slotUpdateAction(action); if ((w = haveWidget("tabbar")) != 0) { w->setEnabled(false); } category->completion()->setSelected(QString()); } // allow kick off VAT processing again - m_inUpdateVat = false; + d->m_inUpdateVat = false; +} + +void StdTransactionEditor::loadEditWidgets() +{ + loadEditWidgets(KMyMoneyRegister::ActionNone); } QWidget* StdTransactionEditor::firstWidget() const { + Q_D(const StdTransactionEditor); QWidget* w = 0; - if (m_initialAction != KMyMoneyRegister::ActionNone) { + if (d->m_initialAction != KMyMoneyRegister::ActionNone) { w = haveWidget("payee"); } return w; } void StdTransactionEditor::slotReloadEditWidgets() { + Q_D(StdTransactionEditor); // reload category widget - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); + KMyMoneyCategory* category = dynamic_cast(d->m_editWidgets["category"]); QString categoryId = category->selectedItem(); AccountSet aSet; aSet.addAccountGroup(eMyMoney::Account::Asset); aSet.addAccountGroup(eMyMoney::Account::Liability); aSet.addAccountGroup(eMyMoney::Account::Income); aSet.addAccountGroup(eMyMoney::Account::Expense); if (KMyMoneyGlobalSettings::expertMode()) aSet.addAccountGroup(eMyMoney::Account::Equity); aSet.load(category->selector()); // if an account is specified then remove it from the widget so that the user // cannot create a transfer with from and to account being the same account - if (!m_account.id().isEmpty()) - category->selector()->removeItem(m_account.id()); + if (!d->m_account.id().isEmpty()) + category->selector()->removeItem(d->m_account.id()); if (!categoryId.isEmpty()) category->setSelectedItem(categoryId); // reload payee widget - KMyMoneyPayeeCombo* payee = dynamic_cast(m_editWidgets["payee"]); + KMyMoneyPayeeCombo* payee = dynamic_cast(d->m_editWidgets["payee"]); QString payeeId = payee->selectedItem(); payee->loadPayees(MyMoneyFile::instance()->payeeList()); if (!payeeId.isEmpty()) { payee->setSelectedItem(payeeId); } // reload tag widget - KTagContainer* tag = dynamic_cast(m_editWidgets["tag"]); + KTagContainer* tag = dynamic_cast(d->m_editWidgets["tag"]); QString tagId = tag->tagCombo()->selectedItem(); tag->loadTags(MyMoneyFile::instance()->tagList()); if (!tagId.isEmpty()) { tag->RemoveAllTagWidgets(); tag->addTagWidget(tagId); } } void StdTransactionEditor::slotUpdatePayee(const QString& payeeId) { + Q_D(StdTransactionEditor); // we have a new payee assigned to this transaction. // in case there is no category assigned, no value entered and no // memo available, we search for the last transaction of this payee // in the account. - if (m_transaction.id().isEmpty() - && m_splits.count() == 0 + if (d->m_transaction.id().isEmpty() + && d->m_splits.count() == 0 && KMyMoneyGlobalSettings::autoFillTransaction() != 0) { // check if category is empty - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); + KMyMoneyCategory* category = dynamic_cast(d->m_editWidgets["category"]); QStringList list; category->selectedItems(list); if (!list.isEmpty()) return; // check if memo is empty - KTextEdit* memo = dynamic_cast(m_editWidgets["memo"]); + KTextEdit* memo = dynamic_cast(d->m_editWidgets["memo"]); if (memo && !memo->toPlainText().isEmpty()) return; // check if all value fields are empty kMyMoneyEdit* amount; QStringList fields; fields << "amount" << "payment" << "deposit"; QStringList::const_iterator it_f; for (it_f = fields.constBegin(); it_f != fields.constEnd(); ++it_f) { amount = dynamic_cast(haveWidget(*it_f)); if (amount && !amount->value().isZero()) return; } #if 0 // Tony mentioned, that autofill does not work when he changed the date. Well, // that certainly makes sense when you enter transactions in register mode as // opposed to form mode, because the date field is located prior to the date // field in the tab order of the widgets and the user might have already // changed it. // // So I commented out the code that checks the date but left it in for reference. // (ipwizard, 2008-04-07) // check if date has been altered by user kMyMoneyDateInput* postDate = dynamic_cast(m_editWidgets["postdate"]); if ((m_lastPostDate.isValid() && (postDate->date() != m_lastPostDate)) || (!m_lastPostDate.isValid() && (postDate->date() != QDate::currentDate()))) return; #endif // if we got here, we have to autofill autoFill(payeeId); } // If payee has associated default account (category), set that now. const MyMoneyPayee& payeeObj = MyMoneyFile::instance()->payee(payeeId); if (payeeObj.defaultAccountEnabled()) { - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); + KMyMoneyCategory* category = dynamic_cast(d->m_editWidgets["category"]); category->slotItemSelected(payeeObj.defaultAccountId()); } } MyMoneyMoney StdTransactionEditor::shares(const MyMoneyTransaction& t) const { + Q_D(const StdTransactionEditor); MyMoneyMoney result; QList::const_iterator it_s; for (it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) { - if ((*it_s).accountId() == m_account.id()) { + if ((*it_s).accountId() == d->m_account.id()) { result += (*it_s).shares(); } } return result; } struct uniqTransaction { const MyMoneyTransaction* t; int cnt; }; void StdTransactionEditor::autoFill(const QString& payeeId) { + Q_D(StdTransactionEditor); QList > list; - MyMoneyTransactionFilter filter(m_account.id()); + MyMoneyTransactionFilter filter(d->m_account.id()); filter.addPayee(payeeId); MyMoneyFile::instance()->transactionList(list, filter); if (!list.empty()) { // ok, we found at least one previous transaction. now we clear out // what we have collected so far and add those splits from // the previous transaction. QList >::const_iterator it_t; QMap uniqList; // collect the transactions and see if we have any duplicates for (it_t = list.constBegin(); it_t != list.constEnd(); ++it_t) { QString key = (*it_t).first.accountSignature(); int cnt = 0; QMap::iterator it_u; do { QString ukey = QString("%1-%2").arg(key).arg(cnt); it_u = uniqList.find(ukey); if (it_u == uniqList.end()) { uniqList[ukey].t = &((*it_t).first); uniqList[ukey].cnt = 1; } else if (KMyMoneyGlobalSettings::autoFillTransaction() == 1) { // we already have a transaction with this signature. we must // now check, if we should really treat it as a duplicate according // to the value comparison delta. MyMoneyMoney s1 = shares(*((*it_u).t)); MyMoneyMoney s2 = shares((*it_t).first); if (s2.abs() > s1.abs()) { MyMoneyMoney t(s1); s1 = s2; s2 = t; } MyMoneyMoney diff; if (s2.isZero()) diff = s1.abs(); else diff = ((s1 - s2) / s2).convert(10000); if (diff.isPositive() && diff <= MyMoneyMoney(KMyMoneyGlobalSettings::autoFillDifference(), 100)) { uniqList[ukey].t = &((*it_t).first); break; // end while loop } } else if (KMyMoneyGlobalSettings::autoFillTransaction() == 2) { (*it_u).cnt++; break; // end while loop } ++cnt; } while (it_u != uniqList.end()); } MyMoneyTransaction t; if (KMyMoneyGlobalSettings::autoFillTransaction() != 2) { #if 0 // I removed this code to allow cancellation of an autofill if // it does not match even if there is only a single matching // transaction for the payee in question. In case, we want to revert // to the old behavior, don't forget to uncomment the closing // brace further down in the code as well. (ipwizard 2009-01-16) if (uniqList.count() == 1) { t = list.last().first; } else { #endif - QPointer dlg = new KSelectTransactionsDlg(m_account, m_regForm); + QPointer dlg = new KSelectTransactionsDlg(d->m_account, d->m_regForm); dlg->setWindowTitle(i18n("Select autofill transaction")); QMap::const_iterator it_u; for (it_u = uniqList.constBegin(); it_u != uniqList.constEnd(); ++it_u) { dlg->addTransaction(*(*it_u).t); } + auto tRegister = dlg->getRegister(); // setup sort order - dlg->m_register->setSortOrder("1,-9,-4"); + tRegister->setSortOrder("1,-9,-4"); // sort the transactions according to the sort setting - dlg->m_register->sortItems(); + tRegister->sortItems(); // and select the last item - if (dlg->m_register->lastItem()) - dlg->m_register->selectItem(dlg->m_register->lastItem()); + if (tRegister->lastItem()) + tRegister->selectItem(tRegister->lastItem()); if (dlg->exec() == QDialog::Accepted) { t = dlg->transaction(); } #if 0 } #endif } else { int maxCnt = 0; QMap::const_iterator it_u; for (it_u = uniqList.constBegin(); it_u != uniqList.constEnd(); ++it_u) { if ((*it_u).cnt > maxCnt) { t = *(*it_u).t; maxCnt = (*it_u).cnt; } } } if (t != MyMoneyTransaction()) { - m_transaction.removeSplits(); - m_split = MyMoneySplit(); + d->m_transaction.removeSplits(); + d->m_split = MyMoneySplit(); MyMoneySplit otherSplit; QList::ConstIterator it; for (it = t.splits().constBegin(); it != t.splits().constEnd(); ++it) { MyMoneySplit s(*it); s.setReconcileFlag(eMyMoney::Split::State::NotReconciled); s.setReconcileDate(QDate()); s.clearId(); s.setBankID(QString()); // older versions of KMyMoney used to set the action // we don't need this anymore if (s.action() != MyMoneySplit::ActionAmortization && s.action() != MyMoneySplit::ActionInterest) { s.setAction(QString()); } // FIXME update check number. The old comment contained // // // If a check number is already specified by the user it is // used. If the input field is empty and the previous transaction // contains a checknumber, the next usable check number will be assigned // to the transaction. // kMyMoneyLineEdit* editNr = dynamic_cast(haveWidget("number")); if (editNr && !editNr->text().isEmpty()) { s.setNumber(editNr->text()); } else if (!s.number().isEmpty()) { - s.setNumber(KMyMoneyUtils::nextCheckNumber(m_account)); + s.setNumber(KMyMoneyUtils::nextCheckNumber(d->m_account)); } // if the memos should not be used with autofill or // if the transaction has exactly two splits, remove // the memo text of the split that does not reference // the current account. This allows the user to change // the autofilled memo text which will then also be used // in this split. See createTransaction() for this logic. - if ((s.accountId() != m_account.id() && t.splitCount() == 2) || !KMyMoneyGlobalSettings::autoFillUseMemos()) + if ((s.accountId() != d->m_account.id() && t.splitCount() == 2) || !KMyMoneyGlobalSettings::autoFillUseMemos()) s.setMemo(QString()); - m_transaction.addSplit(s); - if (s.accountId() == m_account.id() && m_split == MyMoneySplit()) { - m_split = s; + d->m_transaction.addSplit(s); + if (s.accountId() == d->m_account.id() && d->m_split == MyMoneySplit()) { + d->m_split = s; } else { otherSplit = s; } } // make sure to extract the right action KMyMoneyRegister::Action action; - action = m_split.shares().isNegative() ? KMyMoneyRegister::ActionWithdrawal : KMyMoneyRegister::ActionDeposit; + action = d->m_split.shares().isNegative() ? KMyMoneyRegister::ActionWithdrawal : KMyMoneyRegister::ActionDeposit; - if (m_transaction.splitCount() == 2) { + if (d->m_transaction.splitCount() == 2) { MyMoneyAccount acc = MyMoneyFile::instance()->account(otherSplit.accountId()); if (acc.isAssetLiability()) action = KMyMoneyRegister::ActionTransfer; } // now setup the widgets with the new data but keep the date - QDate date = dynamic_cast(m_editWidgets["postdate"])->date(); + QDate date = dynamic_cast(d->m_editWidgets["postdate"])->date(); loadEditWidgets(action); - dynamic_cast(m_editWidgets["postdate"])->setDate(date); + dynamic_cast(d->m_editWidgets["postdate"])->setDate(date); } } // focus jumps into the category field QWidget* w; if ((w = haveWidget("payee")) != 0) { w->setFocus(); } } void StdTransactionEditor::slotUpdateAction(int action) { + Q_D(StdTransactionEditor); TabBar* tabbar = dynamic_cast(haveWidget("tabbar")); if (tabbar) { QLabel* categoryLabel = dynamic_cast(haveWidget("category-label")); - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(m_editWidgets["cashflow"]); + KMyMoneyCashFlowCombo* cashflow = dynamic_cast(d->m_editWidgets["cashflow"]); switch (action) { case KMyMoneyRegister::ActionDeposit: categoryLabel->setText(i18n("Category")); cashflow->setDirection(KMyMoneyRegister::Deposit); break; case KMyMoneyRegister::ActionTransfer: - if (m_split.shares().isNegative()) { + if (d->m_split.shares().isNegative()) { cashflow->setDirection(KMyMoneyRegister::Payment); categoryLabel->setText(i18n("Transfer to")); } else { cashflow->setDirection(KMyMoneyRegister::Deposit); categoryLabel->setText(i18n("Transfer from")); } tabbar->setCurrentIndex(KMyMoneyRegister::ActionTransfer); slotUpdateCashFlow(cashflow->direction()); break; case KMyMoneyRegister::ActionWithdrawal: categoryLabel->setText(i18n("Category")); cashflow->setDirection(KMyMoneyRegister::Payment); break; } resizeForm(); } } void StdTransactionEditor::slotUpdateCashFlow(KMyMoneyRegister::CashFlowDirection dir) { QLabel* categoryLabel = dynamic_cast(haveWidget("category-label")); KMyMoneyCashFlowCombo* cashflow = dynamic_cast(haveWidget("cashflow")); cashflow->setDirection(dir); // qDebug("Update cashflow to %d", dir); if (categoryLabel) { TabBar* tabbar = dynamic_cast(haveWidget("tabbar")); if (!tabbar) return; // no transaction form if (categoryLabel->text() != i18n("Category")) { tabbar->setCurrentIndex(KMyMoneyRegister::ActionTransfer); if (dir == KMyMoneyRegister::Deposit) { categoryLabel->setText(i18n("Transfer from")); } else { categoryLabel->setText(i18n("Transfer to")); } resizeForm(); } else { if (dir == KMyMoneyRegister::Deposit) tabbar->setCurrentIndex(KMyMoneyRegister::ActionDeposit); else tabbar->setCurrentIndex(KMyMoneyRegister::ActionWithdrawal); } } } void StdTransactionEditor::slotUpdateCategory(const QString& id) { + Q_D(StdTransactionEditor); QLabel *categoryLabel = dynamic_cast(haveWidget("category-label")); // qDebug("Update category to %s", qPrintable(id)); if (categoryLabel) { TabBar* tabbar = dynamic_cast(haveWidget("tabbar")); - kMyMoneyEdit* amount = dynamic_cast(m_editWidgets["amount"]); + kMyMoneyEdit* amount = dynamic_cast(d->m_editWidgets["amount"]); MyMoneyMoney val = amount->value(); if (categoryLabel->text() == i18n("Transfer from")) { val = -val; } else { val = val.abs(); } if (tabbar) { tabbar->setTabEnabled(KMyMoneyRegister::ActionTransfer, true); tabbar->setTabEnabled(KMyMoneyRegister::ActionDeposit, true); tabbar->setTabEnabled(KMyMoneyRegister::ActionWithdrawal, true); } bool disableTransferTab = false; if (!id.isEmpty()) { MyMoneyAccount acc = MyMoneyFile::instance()->account(id); if (acc.isAssetLiability() || acc.accountGroup() == eMyMoney::Account::Equity) { if (tabbar) { tabbar->setCurrentIndex(KMyMoneyRegister::ActionTransfer); tabbar->setTabEnabled(KMyMoneyRegister::ActionDeposit, false); tabbar->setTabEnabled(KMyMoneyRegister::ActionWithdrawal, false); } - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(m_editWidgets["cashflow"]); + KMyMoneyCashFlowCombo* cashflow = dynamic_cast(d->m_editWidgets["cashflow"]); if (val.isZero()) { if (cashflow && (cashflow->direction() == KMyMoneyRegister::Deposit)) { categoryLabel->setText(i18n("Transfer from")); } else { categoryLabel->setText(i18n("Transfer to")); } } else if (val.isNegative()) { categoryLabel->setText(i18n("Transfer from")); cashflow->setDirection(KMyMoneyRegister::Deposit); } else categoryLabel->setText(i18n("Transfer to")); } else { disableTransferTab = true; categoryLabel->setText(i18n("Category")); } updateAmount(val); } else { //id.isEmpty() - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); + KMyMoneyCategory* category = dynamic_cast(d->m_editWidgets["category"]); disableTransferTab = !category->currentText().isEmpty(); categoryLabel->setText(i18n("Category")); } if (tabbar) { if (disableTransferTab) { // set the proper tab before disabling the currently active tab if (tabbar->currentIndex() == KMyMoneyRegister::ActionTransfer) { tabbar->setCurrentIndex(val.isPositive() ? KMyMoneyRegister::ActionWithdrawal : KMyMoneyRegister::ActionDeposit); } tabbar->setTabEnabled(KMyMoneyRegister::ActionTransfer, false); } tabbar->update(); } resizeForm(); } updateVAT(false); } void StdTransactionEditor::slotUpdatePayment(const QString& txt) { + Q_D(StdTransactionEditor); MyMoneyMoney val(txt); if (val.isNegative()) { - dynamic_cast(m_editWidgets["deposit"])->setValue(val.abs()); - dynamic_cast(m_editWidgets["payment"])->clearText(); + dynamic_cast(d->m_editWidgets["deposit"])->setValue(val.abs()); + dynamic_cast(d->m_editWidgets["payment"])->clearText(); } else { - dynamic_cast(m_editWidgets["deposit"])->clearText(); + dynamic_cast(d->m_editWidgets["deposit"])->clearText(); } updateVAT(); } void StdTransactionEditor::slotUpdateDeposit(const QString& txt) { + Q_D(StdTransactionEditor); MyMoneyMoney val(txt); if (val.isNegative()) { - dynamic_cast(m_editWidgets["payment"])->setValue(val.abs()); - dynamic_cast(m_editWidgets["deposit"])->clearText(); + dynamic_cast(d->m_editWidgets["payment"])->setValue(val.abs()); + dynamic_cast(d->m_editWidgets["deposit"])->clearText(); } else { - dynamic_cast(m_editWidgets["payment"])->clearText(); + dynamic_cast(d->m_editWidgets["payment"])->clearText(); } updateVAT(); } void StdTransactionEditor::slotUpdateAmount(const QString& txt) { // qDebug("Update amount to %s", qPrintable(txt)); MyMoneyMoney val(txt); updateAmount(val); updateVAT(true); } void StdTransactionEditor::updateAmount(const MyMoneyMoney& val) { // we don't do anything if we have multiple transactions selected if (isMultiSelection()) return; + Q_D(StdTransactionEditor); QLabel *categoryLabel = dynamic_cast(haveWidget("category-label")); if (categoryLabel) { - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(m_editWidgets["cashflow"]); + KMyMoneyCashFlowCombo* cashflow = dynamic_cast(d->m_editWidgets["cashflow"]); if (!val.isPositive()) { // fixes BUG321317 if (categoryLabel->text() != i18n("Category")) { if (cashflow->direction() == KMyMoneyRegister::Payment) { categoryLabel->setText(i18n("Transfer to")); } } else { slotUpdateCashFlow(cashflow->direction()); } - dynamic_cast(m_editWidgets["amount"])->setValue(val.abs()); + dynamic_cast(d->m_editWidgets["amount"])->setValue(val.abs()); } else { if (categoryLabel->text() != i18n("Category")) { if (cashflow->direction() == KMyMoneyRegister::Payment) { categoryLabel->setText(i18n("Transfer to")); } else { categoryLabel->setText(i18n("Transfer from")); cashflow->setDirection(KMyMoneyRegister::Deposit); // editing with +ve shows 'from' not 'pay to' } } - dynamic_cast(m_editWidgets["amount"])->setValue(val.abs()); + dynamic_cast(d->m_editWidgets["amount"])->setValue(val.abs()); } } } void StdTransactionEditor::updateVAT(bool amountChanged) { + Q_D(StdTransactionEditor); // make sure that we don't do this recursively - if (m_inUpdateVat) + if (d->m_inUpdateVat) return; // we don't do anything if we have multiple transactions selected if (isMultiSelection()) return; // if auto vat assignment for this account is turned off // we don't care about taxes - if (m_account.value("NoVat") == "Yes") + if (d->m_account.value("NoVat") == "Yes") return; // more splits than category and tax are not supported - if (m_splits.count() > 2) + if (d->m_splits.count() > 2) return; // in order to do anything, we need an amount MyMoneyMoney amount, newAmount; bool amountOk; amount = amountFromWidget(&amountOk); if (!amountOk) return; // If the transaction has a tax and a category split, remove the tax split - if (m_splits.count() == 2) { + if (d->m_splits.count() == 2) { newAmount = removeVatSplit(); - if (m_splits.count() == 2) // not removed? + if (d->m_splits.count() == 2) // not removed? return; } else { // otherwise, we need a category - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); + KMyMoneyCategory* category = dynamic_cast(d->m_editWidgets["category"]); if (category->selectedItem().isEmpty()) return; // if no VAT account is associated with this category/account, then we bail out MyMoneyAccount cat = MyMoneyFile::instance()->account(category->selectedItem()); if (cat.value("VatAccount").isEmpty()) return; newAmount = amount; } // seems we have everything we need if (amountChanged) newAmount = amount; MyMoneyTransaction transaction; - if (createTransaction(transaction, m_transaction, m_split)) { + if (createTransaction(transaction, d->m_transaction, d->m_split)) { if (addVatSplit(transaction, newAmount)) { - m_transaction = transaction; - if (!m_transaction.splits().isEmpty()) - m_split = m_transaction.splits().front(); + d->m_transaction = transaction; + if (!d->m_transaction.splits().isEmpty()) + d->m_split = d->m_transaction.splits().front(); loadEditWidgets(); // if we made this a split transaction, then move the // focus to the memo field if (qApp->focusWidget() == haveWidget("category")) { QWidget* w = haveWidget("memo"); if (w) w->setFocus(); } } } } bool StdTransactionEditor::addVatSplit(MyMoneyTransaction& tr, const MyMoneyMoney& amount) { if (tr.splitCount() != 2) return false; - MyMoneyFile* file = MyMoneyFile::instance(); + Q_D(StdTransactionEditor); + auto file = MyMoneyFile::instance(); // extract the category split from the transaction - MyMoneyAccount category = file->account(tr.splitByAccount(m_account.id(), false).accountId()); - return file->addVATSplit(tr, m_account, category, amount); + MyMoneyAccount category = file->account(tr.splitByAccount(d->m_account.id(), false).accountId()); + return file->addVATSplit(tr, d->m_account, category, amount); } MyMoneyMoney StdTransactionEditor::removeVatSplit() { + Q_D(StdTransactionEditor); // we only deal with splits that have three splits - if (m_splits.count() != 2) + if (d->m_splits.count() != 2) return amountFromWidget(); MyMoneySplit c; // category split MyMoneySplit t; // tax split bool netValue = false; QList::const_iterator it_s; - for (it_s = m_splits.constBegin(); it_s != m_splits.constEnd(); ++it_s) { + for (it_s = d->m_splits.constBegin(); it_s != d->m_splits.constEnd(); ++it_s) { MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId()); if (!acc.value("VatAccount").isEmpty()) { netValue = (acc.value("VatAmount").toLower() == "net"); c = (*it_s); } else if (!acc.value("VatRate").isEmpty()) { t = (*it_s); } } // bail out if not all splits are setup if (c.id().isEmpty() || t.id().isEmpty()) return amountFromWidget(); MyMoneyMoney amount; // reduce the splits if (netValue) { amount = -c.shares(); } else { amount = -(c.shares() + t.shares()); } // remove tax split from the list, ... - m_splits.clear(); - m_splits.append(c); + d->m_splits.clear(); + d->m_splits.append(c); // ... make sure that the widget is updated ... // block the signals to avoid popping up the split editor dialog // for nothing - m_editWidgets["category"]->blockSignals(true); + d->m_editWidgets["category"]->blockSignals(true); QString id; setupCategoryWidget(id); - m_editWidgets["category"]->blockSignals(false); + d->m_editWidgets["category"]->blockSignals(false); // ... and return the updated amount return amount; } bool StdTransactionEditor::isComplete(QString& reason) const { + Q_D(const StdTransactionEditor); reason.clear(); QMap::const_iterator it_w; - kMyMoneyDateInput* postDate = dynamic_cast(m_editWidgets["postdate"]); + kMyMoneyDateInput* postDate = dynamic_cast(d->m_editWidgets["postdate"]); if (postDate) { - QDate accountOpeningDate = m_account.openingDate(); - for (QList::const_iterator it_s = m_splits.constBegin(); it_s != m_splits.constEnd(); ++it_s) { + QDate accountOpeningDate = d->m_account.openingDate(); + for (QList::const_iterator it_s = d->m_splits.constBegin(); it_s != d->m_splits.constEnd(); ++it_s) { const MyMoneyAccount& acc = MyMoneyFile::instance()->account((*it_s).accountId()); // compute the newest opening date of all accounts involved in the transaction if (acc.openingDate() > accountOpeningDate) accountOpeningDate = acc.openingDate(); } // check the selected category in case m_splits hasn't been updated yet - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); + KMyMoneyCategory* category = dynamic_cast(d->m_editWidgets["category"]); if (category && !category->selectedItem().isEmpty()) { MyMoneyAccount cat = MyMoneyFile::instance()->account(category->selectedItem()); if (cat.openingDate() > accountOpeningDate) accountOpeningDate = cat.openingDate(); } if (postDate->date().isValid() && (postDate->date() < accountOpeningDate)) { postDate->markAsBadDate(true, KMyMoneyGlobalSettings::schemeColor(SchemeColor::Negative)); reason = i18n("Cannot enter transaction with postdate prior to account's opening date."); postDate->setToolTip(reason); return false; } postDate->markAsBadDate(); postDate->setToolTip(""); } - for (it_w = m_editWidgets.begin(); it_w != m_editWidgets.end(); ++it_w) { + for (it_w = d->m_editWidgets.begin(); it_w != d->m_editWidgets.end(); ++it_w) { KMyMoneyPayeeCombo* payee = dynamic_cast(*it_w); KTagContainer* tagContainer = dynamic_cast(*it_w); KMyMoneyCategory* category = dynamic_cast(*it_w); kMyMoneyEdit* amount = dynamic_cast(*it_w); KMyMoneyReconcileCombo* reconcile = dynamic_cast(*it_w); KMyMoneyCashFlowCombo* cashflow = dynamic_cast(*it_w); KTextEdit* memo = dynamic_cast(*it_w); if (payee && !(payee->currentText().isEmpty())) break; if (category && !category->lineEdit()->text().isEmpty()) break; if (amount && !(amount->value().isZero())) break; // the following widgets are only checked if we are editing multiple transactions if (isMultiSelection()) { TabBar* tabbar = dynamic_cast(haveWidget("tabbar")); if (tabbar) { tabbar->setEnabled(true); } if (reconcile && reconcile->state() != eMyMoney::Split::State::Unknown) break; if (cashflow && cashflow->direction() != KMyMoneyRegister::Unknown) break; - if (postDate->date().isValid() && (postDate->date() >= m_account.openingDate())) + if (postDate->date().isValid() && (postDate->date() >= d->m_account.openingDate())) break; - if (memo && m_memoChanged) + if (memo && d->m_memoChanged) break; if (tagContainer && !(tagContainer->selectedTags().isEmpty())) // Tag is optional field break; } } - return it_w != m_editWidgets.end(); + return it_w != d->m_editWidgets.end(); } void StdTransactionEditor::slotCreateCategory(const QString& name, QString& id) { + Q_D(StdTransactionEditor); MyMoneyAccount acc, parent; acc.setName(name); KMyMoneyCashFlowCombo* cashflow = dynamic_cast(haveWidget("cashflow")); if (cashflow) { // form based input if (cashflow->direction() == KMyMoneyRegister::Deposit) parent = MyMoneyFile::instance()->income(); else parent = MyMoneyFile::instance()->expense(); } else if (haveWidget("deposit")) { // register based input - kMyMoneyEdit* deposit = dynamic_cast(m_editWidgets["deposit"]); + kMyMoneyEdit* deposit = dynamic_cast(d->m_editWidgets["deposit"]); if (deposit->value().isPositive()) parent = MyMoneyFile::instance()->income(); else parent = MyMoneyFile::instance()->expense(); } else parent = MyMoneyFile::instance()->expense(); // TODO extract possible first part of a hierarchy and check if it is one // of our top categories. If so, remove it and select the parent // according to this information. emit createCategory(acc, parent); // return id id = acc.id(); } int StdTransactionEditor::slotEditSplits() { + Q_D(StdTransactionEditor); int rc = QDialog::Rejected; - if (!m_openEditSplits) { + if (!d->m_openEditSplits) { // only get in here in a single instance - m_openEditSplits = true; + d->m_openEditSplits = true; // force focus change to update all data - QWidget* w = dynamic_cast(m_editWidgets["category"])->splitButton(); + QWidget* w = dynamic_cast(d->m_editWidgets["category"])->splitButton(); if (w) w->setFocus(); kMyMoneyEdit* amount = dynamic_cast(haveWidget("amount")); kMyMoneyEdit* deposit = dynamic_cast(haveWidget("deposit")); kMyMoneyEdit* payment = dynamic_cast(haveWidget("payment")); KMyMoneyCashFlowCombo* cashflow = 0; KMyMoneyRegister::CashFlowDirection dir = KMyMoneyRegister::Unknown; bool isValidAmount = false; if (amount) { isValidAmount = amount->lineedit()->text().length() != 0; cashflow = dynamic_cast(haveWidget("cashflow")); if (cashflow) dir = cashflow->direction(); } else { if (deposit) { if (deposit->lineedit()->text().length() != 0) { isValidAmount = true; dir = KMyMoneyRegister::Deposit; } } if (payment) { if (payment->lineedit()->text().length() != 0) { isValidAmount = true; dir = KMyMoneyRegister::Payment; } } if (!deposit || !payment) { qDebug("Internal error: deposit(%p) & payment(%p) widgets not found but required", deposit, payment); return rc; } } if (dir == KMyMoneyRegister::Unknown) dir = KMyMoneyRegister::Payment; MyMoneyTransaction transaction; - if (createTransaction(transaction, m_transaction, m_split)) { + if (createTransaction(transaction, d->m_transaction, d->m_split)) { MyMoneyMoney value; QPointer dlg = new KSplitTransactionDlg(transaction, transaction.splits().isEmpty() ? MyMoneySplit() : transaction.splits().front(), - m_account, + d->m_account, isValidAmount, dir == KMyMoneyRegister::Deposit, MyMoneyMoney(), - m_priceInfo, - m_regForm); + d->m_priceInfo, + d->m_regForm); connect(dlg, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); connect(dlg, SIGNAL(createCategory(MyMoneyAccount&,MyMoneyAccount)), this, SIGNAL(createCategory(MyMoneyAccount&,MyMoneyAccount))); if ((rc = dlg->exec()) == QDialog::Accepted) { - m_transaction = dlg->transaction(); - if (!m_transaction.splits().isEmpty()) - m_split = m_transaction.splits().front(); + d->m_transaction = dlg->transaction(); + if (!d->m_transaction.splits().isEmpty()) + d->m_split = d->m_transaction.splits().front(); loadEditWidgets(); } delete dlg; } // focus jumps into the tag field if ((w = haveWidget("tag")) != 0) { w->setFocus(); } - m_openEditSplits = false; + d->m_openEditSplits = false; } return rc; } void StdTransactionEditor::checkPayeeInSplit(MyMoneySplit& s, const QString& payeeId) { if (s.accountId().isEmpty()) return; MyMoneyAccount acc = MyMoneyFile::instance()->account(s.accountId()); if (acc.isIncomeExpense()) { s.setPayeeId(payeeId); } else { if (s.payeeId().isEmpty()) s.setPayeeId(payeeId); } } MyMoneyMoney StdTransactionEditor::amountFromWidget(bool* update) const { + Q_D(const StdTransactionEditor); bool updateValue = false; MyMoneyMoney value; - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(haveWidget("cashflow")); + auto cashflow = dynamic_cast(haveWidget("cashflow")); if (cashflow) { // form based input - kMyMoneyEdit* amount = dynamic_cast(m_editWidgets["amount"]); + auto amount = dynamic_cast(d->m_editWidgets["amount"]); // if both fields do not contain changes -> no need to update if (cashflow->direction() != KMyMoneyRegister::Unknown && !amount->lineedit()->text().isEmpty()) updateValue = true; value = amount->value(); if (cashflow->direction() == KMyMoneyRegister::Payment) value = -value; } else if (haveWidget("deposit")) { // register based input - kMyMoneyEdit* deposit = dynamic_cast(m_editWidgets["deposit"]); - kMyMoneyEdit* payment = dynamic_cast(m_editWidgets["payment"]); + auto deposit = dynamic_cast(d->m_editWidgets["deposit"]); + auto payment = dynamic_cast(d->m_editWidgets["payment"]); // if both fields do not contain text -> no need to update if (!(deposit->lineedit()->text().isEmpty() && payment->lineedit()->text().isEmpty())) updateValue = true; if (deposit->value().isPositive()) value = deposit->value(); else value = -(payment->value()); } if (update) *update = updateValue; // determine the max fraction for this account and // adjust the value accordingly - return value.convert(m_account.fraction()); + return value.convert(d->m_account.fraction()); } bool StdTransactionEditor::createTransaction(MyMoneyTransaction& t, const MyMoneyTransaction& torig, const MyMoneySplit& sorig, bool skipPriceDialog) { + Q_D(StdTransactionEditor); // extract price info from original transaction - m_priceInfo.clear(); + d->m_priceInfo.clear(); QList::const_iterator it_s; if (!torig.id().isEmpty()) { for (it_s = torig.splits().begin(); it_s != torig.splits().end(); ++it_s) { if ((*it_s).id() != sorig.id()) { MyMoneyAccount cat = MyMoneyFile::instance()->account((*it_s).accountId()); - if (cat.currencyId() != m_account.currencyId()) { + if (cat.currencyId() != d->m_account.currencyId()) { if (!(*it_s).shares().isZero() && !(*it_s).value().isZero()) { - m_priceInfo[cat.currencyId()] = ((*it_s).shares() / (*it_s).value()).reduce(); + d->m_priceInfo[cat.currencyId()] = ((*it_s).shares() / (*it_s).value()).reduce(); } } } } } t = torig; t.removeSplits(); - t.setCommodity(m_account.currencyId()); + t.setCommodity(d->m_account.currencyId()); - kMyMoneyDateInput* postDate = dynamic_cast(m_editWidgets["postdate"]); + kMyMoneyDateInput* postDate = dynamic_cast(d->m_editWidgets["postdate"]); if (postDate->date().isValid()) { t.setPostDate(postDate->date()); } // we start with the previous values, make sure we can add them later on MyMoneySplit s0 = sorig; s0.clearId(); // make sure we reference this account here - s0.setAccountId(m_account.id()); + s0.setAccountId(d->m_account.id()); // memo and number field are special: if we have multiple transactions selected // and the edit field is empty, we treat it as "not modified". // FIXME a better approach would be to have a 'dirty' flag with the widgets // which identifies if the originally loaded value has been modified // by the user - KTextEdit* memo = dynamic_cast(m_editWidgets["memo"]); + KTextEdit* memo = dynamic_cast(d->m_editWidgets["memo"]); if (memo) { - if (!isMultiSelection() || (isMultiSelection() && m_memoChanged)) + if (!isMultiSelection() || (isMultiSelection() && d->m_memoChanged)) s0.setMemo(memo->toPlainText()); } kMyMoneyLineEdit* number = dynamic_cast(haveWidget("number")); if (number) { if (!isMultiSelection() || (isMultiSelection() && !number->text().isEmpty())) s0.setNumber(number->text()); } - KMyMoneyPayeeCombo* payee = dynamic_cast(m_editWidgets["payee"]); + KMyMoneyPayeeCombo* payee = dynamic_cast(d->m_editWidgets["payee"]); QString payeeId; if (!isMultiSelection() || (isMultiSelection() && !payee->currentText().isEmpty())) { payeeId = payee->selectedItem(); s0.setPayeeId(payeeId); } //KMyMoneyTagCombo* tag = dynamic_cast(m_editWidgets["tag"]); - KTagContainer* tag = dynamic_cast(m_editWidgets["tag"]); + KTagContainer* tag = dynamic_cast(d->m_editWidgets["tag"]); if (!isMultiSelection() || (isMultiSelection() && !tag->selectedTags().isEmpty())) { s0.setTagIdList(tag->selectedTags()); } bool updateValue; MyMoneyMoney value = amountFromWidget(&updateValue); if (updateValue) { // for this account, the shares and value is the same s0.setValue(value); s0.setShares(value); } else { value = s0.value(); } // if we mark the split reconciled here, we'll use today's date if no reconciliation date is given - KMyMoneyReconcileCombo* status = dynamic_cast(m_editWidgets["status"]); + KMyMoneyReconcileCombo* status = dynamic_cast(d->m_editWidgets["status"]); if (status->state() != eMyMoney::Split::State::Unknown) s0.setReconcileFlag(status->state()); if (s0.reconcileFlag() == eMyMoney::Split::State::Reconciled && !s0.reconcileDate().isValid()) s0.setReconcileDate(QDate::currentDate()); checkPayeeInSplit(s0, payeeId); // add the split to the transaction t.addSplit(s0); // if we have no other split we create it // if we have none or only one other split, we reconstruct it here // if we have more than one other split, we take them as they are // make sure to perform all those changes on a local copy - QList splits = m_splits; + QList splits = d->m_splits; MyMoneySplit s1; if (splits.isEmpty()) { s1.setMemo(s0.memo()); splits.append(s1); // make sure we will fill the value and share fields later on updateValue = true; } // FIXME in multiSelection we currently only support transactions with one // or two splits. So we check the original transaction and extract the other // split or create it if (isMultiSelection()) { if (torig.splitCount() == 2) { QList::const_iterator it_s; for (it_s = torig.splits().begin(); it_s != torig.splits().end(); ++it_s) { if ((*it_s).id() == sorig.id()) continue; s1 = *it_s; s1.clearId(); break; } } } else { if (splits.count() == 1) { s1 = splits[0]; s1.clearId(); } } if (isMultiSelection() || splits.count() == 1) { - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); + KMyMoneyCategory* category = dynamic_cast(d->m_editWidgets["category"]); if (!isMultiSelection() || (isMultiSelection() && !category->currentText().isEmpty())) { s1.setAccountId(category->selectedItem()); } // if the first split has a memo but the second split is empty, // we just copy the memo text over if (memo) { if (!isMultiSelection() || (isMultiSelection() && !memo->toPlainText().isEmpty())) { // if the memo is filled, we check if the // account referenced by s1 is a regular account or a category. // in case of a regular account, we just leave the memo as is // in case of a category we simply copy the new value over the old. // in case we don't even have an account id, we just skip because // the split will be removed later on anyway. if (!s1.memo().isEmpty() && s1.memo() != s0.memo()) { if (!s1.accountId().isEmpty()) { MyMoneyAccount acc = MyMoneyFile::instance()->account(s1.accountId()); if (acc.isIncomeExpense()) s1.setMemo(s0.memo()); - else if (KMessageBox::questionYesNo(m_regForm, + else if (KMessageBox::questionYesNo(d->m_regForm, i18n("Do you want to replace memo

%1

with memo

%2

in the other split?", s1.memo(), s0.memo()), i18n("Copy memo"), KStandardGuiItem::yes(), KStandardGuiItem::no(), QStringLiteral("CopyMemoOver")) == KMessageBox::Yes) s1.setMemo(s0.memo()); } } else { s1.setMemo(s0.memo()); } } } if (updateValue && !s1.accountId().isEmpty()) { s1.setValue(-value); MyMoneyMoney shares; if (!skipPriceDialog) { - if (!KCurrencyCalculator::setupSplitPrice(shares, t, s1, m_priceInfo, m_regForm)) + if (!KCurrencyCalculator::setupSplitPrice(shares, t, s1, d->m_priceInfo, d->m_regForm)) return false; } else { MyMoneyAccount cat = MyMoneyFile::instance()->account(s1.accountId()); - if (m_priceInfo.find(cat.currencyId()) != m_priceInfo.end()) { - shares = (s1.value() * m_priceInfo[cat.currencyId()]).reduce().convert(cat.fraction()); + if (d->m_priceInfo.find(cat.currencyId()) != d->m_priceInfo.end()) { + shares = (s1.value() * d->m_priceInfo[cat.currencyId()]).reduce().convert(cat.fraction()); } else shares = s1.value(); } s1.setShares(shares); } checkPayeeInSplit(s1, payeeId); if (!s1.accountId().isEmpty()) t.addSplit(s1); } else { QList::iterator it_s; for (it_s = splits.begin(); it_s != splits.end(); ++it_s) { s1 = *it_s; s1.clearId(); checkPayeeInSplit(s1, payeeId); t.addSplit(s1); } } return true; } void StdTransactionEditor::setupFinalWidgets() { addFinalWidget(haveWidget("deposit")); addFinalWidget(haveWidget("payment")); addFinalWidget(haveWidget("amount")); addFinalWidget(haveWidget("status")); } void StdTransactionEditor::slotUpdateAccount(const QString& id) { + Q_D(StdTransactionEditor); TransactionEditor::slotUpdateAccount(id); - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); + KMyMoneyCategory* category = dynamic_cast(d->m_editWidgets["category"]); if (category && category->splitButton()) { category->splitButton()->setDisabled(id.isEmpty()); } } diff --git a/kmymoney/dialogs/stdtransactioneditor.h b/kmymoney/dialogs/stdtransactioneditor.h new file mode 100644 index 000000000..7bcc1ffd2 --- /dev/null +++ b/kmymoney/dialogs/stdtransactioneditor.h @@ -0,0 +1,162 @@ +/*************************************************************************** + stdtransactioneditor.h + ---------- + begin : Wed Jun 07 2006 + copyright : (C) 2006 by Thomas Baumgart + email : Thomas Baumgart + (C) 2017 by Ł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. * + * * + ***************************************************************************/ + +#ifndef STDTRANSACTIONEDITOR_H +#define STDTRANSACTIONEDITOR_H + +// ---------------------------------------------------------------------------- +// QT Includes + +// ---------------------------------------------------------------------------- +// KDE Includes + +// ---------------------------------------------------------------------------- +// Project Includes + +#include "transactioneditor.h" + +class MyMoneyMoney; + +namespace KMyMoneyRegister { enum CashFlowDirection : int; } + +class StdTransactionEditorPrivate; +class StdTransactionEditor : public TransactionEditor +{ + Q_OBJECT +public: + StdTransactionEditor(); + explicit StdTransactionEditor(TransactionEditorContainer* regForm, + KMyMoneyRegister::Transaction* item, + const KMyMoneyRegister::SelectedTransactions& list, + const QDate& lastPostDate); + ~StdTransactionEditor() override; + + bool isComplete(QString& reason) const override; + QWidget* firstWidget() const override; + + /** + * This method creates a transaction based on the contents of the current widgets, + * the splits in m_split in single selection mode or an existing transaction/split + * and the contents of the widgets in multi selection mode. + * + * The split referencing the current account is returned as the first split in the + * transaction's split list. + * + * @param t reference to created transaction + * @param torig the original transaction + * @param sorig the original split + * @param skipPriceDialog if @p true the user will not be requested for price information + * (defaults to @p false) + * + * @return @p false if aborted by user, @p true otherwise + * + * @note Usually not used directly. If unsure, use enterTransactions() instead. + */ + bool createTransaction(MyMoneyTransaction& t, + const MyMoneyTransaction& torig, + const MyMoneySplit& sorig, + bool skipPriceDialog = false) override; + +public slots: + int slotEditSplits() override; + void slotUpdateAmount(const QString&); + +protected slots: + void slotReloadEditWidgets(); + void slotUpdatePayment(const QString&); + void slotUpdateDeposit(const QString&); + void slotUpdateCategory(const QString&); + void slotUpdatePayee(const QString&); + //void slotUpdateTag(const QString&); + void slotUpdateCashFlow(KMyMoneyRegister::CashFlowDirection); + void slotCreateCategory(const QString&, QString&); + void slotUpdateAction(int action); + void slotUpdateAccount(const QString& id) override; + +protected: + /** + * This method creates all necessary widgets for this transaction editor. + * All signals will be connected to the relevant slots. + */ + void createEditWidgets() override; + + /** + * This method (re-)loads the widgets with the transaction information + * contained in @a m_transaction and @a m_split. + * + * @param action preset the edit wigdets for @a action if no transaction + * is present + */ + void loadEditWidgets(KMyMoneyRegister::Action action) override; + void loadEditWidgets() override; + + void setupCategoryWidget(QString&); + void updateAmount(const MyMoneyMoney& value); + bool isTransfer(const QString& accId1, const QString& accId2) const; + + void checkPayeeInSplit(MyMoneySplit& s, const QString& payeeId); + + /** + * This method fills the editor widgets with the last transaction + * that can be found for payee @a payeeId in the account @a m_account. + */ + void autoFill(const QString& payeeId); + + /** + * Extracts the amount of the transaction from the widgets depending + * if form or register based input method is used. + * Returns if an amount has been found in @a update. + * + * @param update pointer to update information flag + * @return amount of transaction (deposit positive, payment negative) + */ + MyMoneyMoney amountFromWidget(bool* update = 0) const; + + /** + * Create or update a VAT split + */ + void updateVAT(bool amountChanged = true); + + MyMoneyMoney removeVatSplit(); + + /** + * This method adds a VAT split to transaction @a tr if necessary. + * + * @param tr transaction that the split should be added to + * @param amount Amount to be used for the calculation. Depending upon the + * setting of the resp. category, this value is treated as + * either gross or net value. + * @retval false VAT split has not been added + * @retval true VAT split has been added + */ + bool addVatSplit(MyMoneyTransaction& tr, const MyMoneyMoney& amount); + + void setupFinalWidgets() override; + + /** + * This method returns the sum of all splits of transaction @a t that + * reference account m_account. + */ + MyMoneyMoney shares(const MyMoneyTransaction& t) const; + +private: + Q_DECLARE_PRIVATE(StdTransactionEditor) +}; + + +#endif diff --git a/kmymoney/dialogs/transactioneditor.cpp b/kmymoney/dialogs/transactioneditor.cpp index 2b37f0a55..ef85fb9a7 100644 --- a/kmymoney/dialogs/transactioneditor.cpp +++ b/kmymoney/dialogs/transactioneditor.cpp @@ -1,2297 +1,825 @@ /*************************************************************************** transactioneditor.cpp ---------- begin : Wed Jun 07 2006 copyright : (C) 2006 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "transactioneditor.h" +#include "transactioneditor_p.h" // ---------------------------------------------------------------------------- // QT Includes -#include #include #include -#include #include #include #include -#include -#include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include -#include #include #include #include // ---------------------------------------------------------------------------- // Project Includes #include "mymoneyutils.h" #include "kmymoneycategory.h" #include "kmymoneymvccombo.h" -#include "kmymoneydateinput.h" #include "kmymoneyedit.h" #include "kmymoneylineedit.h" -#include -#include "kmymoneyaccountselector.h" #include "mymoneyfile.h" #include "mymoneyprice.h" #include "mymoneysecurity.h" -#include "mymoneypayee.h" -#include "mymoneytag.h" -#include "mymoneyschedule.h" #include "kmymoneyutils.h" +#include "kmymoneycompletion.h" #include "transactionform.h" #include "kmymoneyglobalsettings.h" #include "transactioneditorcontainer.h" -#include "ksplittransactiondlg.h" #include "kcurrencycalculator.h" -#include "kselecttransactionsdlg.h" #include "icons.h" using namespace KMyMoneyRegister; using namespace KMyMoneyTransactionForm; using namespace Icons; TransactionEditor::TransactionEditor() : - m_paymentMethod(eMyMoney::Schedule::PaymentType::Any), - m_regForm(0), - m_item(0), - m_initialAction(ActionNone), - m_openEditSplits(false), - m_memoChanged(false) + d_ptr(new TransactionEditorPrivate(this)) { + Q_D(TransactionEditor); + d->init(); } -TransactionEditor::TransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::Transaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate) : - m_paymentMethod(eMyMoney::Schedule::PaymentType::Any), - m_transactions(list), - m_regForm(regForm), - m_item(item), - m_transaction(item->transaction()), - m_split(item->split()), - m_lastPostDate(lastPostDate), - m_initialAction(ActionNone), - m_openEditSplits(false), - m_memoChanged(false) +TransactionEditor::TransactionEditor(TransactionEditorPrivate &dd, + TransactionEditorContainer* regForm, + KMyMoneyRegister::Transaction* item, + const KMyMoneyRegister::SelectedTransactions& list, + const QDate& lastPostDate) : + d_ptr(&dd) +// d_ptr(new TransactionEditorPrivate) { - m_item->startEditMode(); - connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotUpdateAccount())); + Q_D(TransactionEditor); + d->m_paymentMethod = eMyMoney::Schedule::PaymentType::Any; + d->m_transactions = list; + d->m_regForm = regForm; + d->m_item = item; + d->m_transaction = item->transaction(); + d->m_split = item->split(); + d->m_lastPostDate = lastPostDate; + d->m_initialAction = ActionNone; + d->m_openEditSplits = false; + d->m_memoChanged = false; + d->m_item->startEditMode(); + connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, this, static_cast(&TransactionEditor::slotUpdateAccount)); +} + +TransactionEditor::TransactionEditor(TransactionEditorPrivate &dd) : + d_ptr(&dd) +{ + Q_D(TransactionEditor); + d->init(); } TransactionEditor::~TransactionEditor() { + Q_D(TransactionEditor); // Make sure the widgets do not send out signals to the editor anymore // After all, the editor is about to die //disconnect first tagCombo: KTagContainer *w = dynamic_cast(haveWidget("tag")); if (w && w->tagCombo()) { w->tagCombo()->disconnect(this); } QMap::iterator it_w; - for (it_w = m_editWidgets.begin(); it_w != m_editWidgets.end(); ++it_w) { + for (it_w = d->m_editWidgets.begin(); it_w != d->m_editWidgets.end(); ++it_w) { (*it_w)->disconnect(this); } - m_regForm->removeEditWidgets(m_editWidgets); - m_item->leaveEditMode(); - emit finishEdit(m_transactions); + d->m_regForm->removeEditWidgets(d->m_editWidgets); + d->m_item->leaveEditMode(); + emit finishEdit(d->m_transactions); } void TransactionEditor::slotUpdateAccount(const QString& id) { - m_account = MyMoneyFile::instance()->account(id); + Q_D(TransactionEditor); + d->m_account = MyMoneyFile::instance()->account(id); setupPrecision(); } void TransactionEditor::slotUpdateAccount() { + Q_D(TransactionEditor); // reload m_account as it might have been changed - m_account = MyMoneyFile::instance()->account(m_account.id()); + d->m_account = MyMoneyFile::instance()->account(d->m_account.id()); setupPrecision(); } void TransactionEditor::setupPrecision() { - const int prec = (m_account.id().isEmpty()) ? 2 : MyMoneyMoney::denomToPrec(m_account.fraction()); + Q_D(TransactionEditor); + const int prec = (d->m_account.id().isEmpty()) ? 2 : MyMoneyMoney::denomToPrec(d->m_account.fraction()); QStringList widgets = QString("amount,deposit,payment").split(','); QStringList::const_iterator it_w; for (it_w = widgets.constBegin(); it_w != widgets.constEnd(); ++it_w) { QWidget * w; if ((w = haveWidget(*it_w)) != 0) { dynamic_cast(w)->setPrecision(prec); } } } void TransactionEditor::setup(QWidgetList& tabOrderWidgets, const MyMoneyAccount& account, KMyMoneyRegister::Action action) { - m_account = account; - m_initialAction = action; + Q_D(TransactionEditor); + d->m_account = account; + d->m_initialAction = action; createEditWidgets(); - m_regForm->arrangeEditWidgets(m_editWidgets, m_item); - m_regForm->tabOrder(tabOrderWidgets, m_item); + d->m_regForm->arrangeEditWidgets(d->m_editWidgets, d->m_item); + d->m_regForm->tabOrder(tabOrderWidgets, d->m_item); QWidget* w = haveWidget("tabbar"); if (w) { tabOrderWidgets.append(w); TabBar* tabbar = dynamic_cast(w); if ((tabbar) && (action == KMyMoneyRegister::ActionNone)) { action = static_cast(tabbar->currentIndex()); } } loadEditWidgets(action); // remove all unused widgets and don't forget to remove them // from the tab order list as well - m_editWidgets.removeOrphans(); + d->m_editWidgets.removeOrphans(); QWidgetList::iterator it_w; - const QWidgetList editWidgets(m_editWidgets.values()); + const QWidgetList editWidgets(d->m_editWidgets.values()); for (it_w = tabOrderWidgets.begin(); it_w != tabOrderWidgets.end();) { if (editWidgets.contains(*it_w)) { ++it_w; } else { // before we remove the widget, we make sure it's not a part of a known one. // these could be a direct child in case of KMyMoneyDateInput and KMyMoneyEdit // where we store the pointer to the surrounding frame in editWidgets // or the parent is called "KMyMoneyCategoryFrame" if (*it_w) { if (editWidgets.contains((*it_w)->parentWidget()) || ((*it_w)->parentWidget() && (*it_w)->parentWidget()->objectName() == QLatin1String("KMyMoneyCategoryFrame"))) { ++it_w; } else { // qDebug("Remove '%s' from taborder", qPrintable((*it_w)->objectName())); it_w = tabOrderWidgets.erase(it_w); } } else { it_w = tabOrderWidgets.erase(it_w); } } } clearFinalWidgets(); setupFinalWidgets(); slotUpdateButtonState(); } +void TransactionEditor::setup(QWidgetList& tabOrderWidgets, const MyMoneyAccount& account) +{ + setup(tabOrderWidgets, account, KMyMoneyRegister::ActionNone); +} + +void TransactionEditor::setup(QWidgetList& tabOrderWidgets) +{ + setup(tabOrderWidgets, MyMoneyAccount(), KMyMoneyRegister::ActionNone); +} + +MyMoneyAccount TransactionEditor::account() const +{ + Q_D(const TransactionEditor); + return d->m_account; +} + +void TransactionEditor::setScheduleInfo(const QString& si) +{ + Q_D(TransactionEditor); + d->m_scheduleInfo = si; +} + +void TransactionEditor::setPaymentMethod(eMyMoney::Schedule::PaymentType pm) +{ + Q_D(TransactionEditor); + d->m_paymentMethod = pm; +} + void TransactionEditor::clearFinalWidgets() { - m_finalEditWidgets.clear(); + Q_D(TransactionEditor); + d->m_finalEditWidgets.clear(); } void TransactionEditor::addFinalWidget(const QWidget* w) { + Q_D(TransactionEditor); if (w) { - m_finalEditWidgets << w; + d->m_finalEditWidgets << w; } } void TransactionEditor::slotReloadEditWidgets() { } bool TransactionEditor::eventFilter(QObject* o, QEvent* e) { + Q_D(TransactionEditor); bool rc = false; if (o == haveWidget("number")) { if (e->type() == QEvent::MouseButtonDblClick) { emit assignNumber(); rc = true; } } // if the object is a widget, the event is a key press event and // the object is one of our edit widgets, then .... if (o->isWidgetType() && (e->type() == QEvent::KeyPress) - && m_editWidgets.values().contains(dynamic_cast(o))) { + && d->m_editWidgets.values().contains(dynamic_cast(o))) { QKeyEvent* k = dynamic_cast(e); if ((k->modifiers() & Qt::KeyboardModifierMask) == 0 || (k->modifiers() & Qt::KeypadModifier) != 0) { bool isFinal = false; QList::const_iterator it_w; switch (k->key()) { case Qt::Key_Return: case Qt::Key_Enter: // we check, if the object is one of the m_finalEditWidgets and if it's // a kMyMoneyEdit object that the value is not 0. If any of that is the // case, it's the final object. In other cases, we convert the enter // key into a TAB key to move between the fields. Of course, we only need // to do this as long as the appropriate option is set. In all other cases, // we treat the return/enter key as such. if (KMyMoneyGlobalSettings::enterMovesBetweenFields()) { - for (it_w = m_finalEditWidgets.constBegin(); !isFinal && it_w != m_finalEditWidgets.constEnd(); ++it_w) { + for (it_w = d->m_finalEditWidgets.constBegin(); !isFinal && it_w != d->m_finalEditWidgets.constEnd(); ++it_w) { if (*it_w == o) { if (dynamic_cast(*it_w)) { isFinal = !(dynamic_cast(*it_w)->value().isZero()); } else isFinal = true; } } } else isFinal = true; // for the non-final objects, we treat the return key as a TAB if (!isFinal) { QKeyEvent evt(e->type(), Qt::Key_Tab, k->modifiers(), QString(), k->isAutoRepeat(), k->count()); QApplication::sendEvent(o, &evt); // in case of a category item and the split button is visible // send a second event so that we get passed the button. if (dynamic_cast(o) && dynamic_cast(o)->splitButton()) QApplication::sendEvent(o, &evt); } else { QTimer::singleShot(0, this, SIGNAL(returnPressed())); } // don't process any further rc = true; break; case Qt::Key_Escape: QTimer::singleShot(0, this, SIGNAL(escapePressed())); break; } } } return rc; } void TransactionEditor::slotNumberChanged(const QString& txt) { - QString next = txt; + Q_D(TransactionEditor); + auto next = txt; kMyMoneyLineEdit* number = dynamic_cast(haveWidget("number")); QString schedInfo; - if (!m_scheduleInfo.isEmpty()) { - schedInfo = i18n("
Processing schedule for %1.
", m_scheduleInfo); + if (!d->m_scheduleInfo.isEmpty()) { + schedInfo = i18n("
Processing schedule for %1.
", d->m_scheduleInfo); } - while (MyMoneyFile::instance()->checkNoUsed(m_account.id(), next)) { - if (KMessageBox::questionYesNo(m_regForm, QString("") + schedInfo + i18n("
Check number %1 has already been used in account %2.
" - "
Do you want to replace it with the next available number?
", next, m_account.name()) + QString("
"), i18n("Duplicate number")) == KMessageBox::Yes) { + while (MyMoneyFile::instance()->checkNoUsed(d->m_account.id(), next)) { + if (KMessageBox::questionYesNo(d->m_regForm, QString("") + schedInfo + i18n("
Check number %1 has already been used in account %2.
" + "
Do you want to replace it with the next available number?
", next, d->m_account.name()) + QString("
"), i18n("Duplicate number")) == KMessageBox::Yes) { assignNextNumber(); - next = KMyMoneyUtils::nextCheckNumber(m_account); + next = KMyMoneyUtils::nextCheckNumber(d->m_account); } else { number->setText(QString()); break; } } } void TransactionEditor::slotUpdateMemoState() { - KTextEdit* memo = dynamic_cast(m_editWidgets["memo"]); + Q_D(TransactionEditor); + KTextEdit* memo = dynamic_cast(d->m_editWidgets["memo"]); if (memo) { - m_memoChanged = (memo->toPlainText() != m_memoText); + d->m_memoChanged = (memo->toPlainText() != d->m_memoText); } } void TransactionEditor::slotUpdateButtonState() { QString reason; emit transactionDataSufficient(isComplete(reason)); } QWidget* TransactionEditor::haveWidget(const QString& name) const { - return m_editWidgets.haveWidget(name); + Q_D(const TransactionEditor); + return d->m_editWidgets.haveWidget(name); } int TransactionEditor::slotEditSplits() { return QDialog::Rejected; } void TransactionEditor::setTransaction(const MyMoneyTransaction& t, const MyMoneySplit& s) { - m_transaction = t; - m_split = s; + Q_D(TransactionEditor); + d->m_transaction = t; + d->m_split = s; loadEditWidgets(); } +bool TransactionEditor::isMultiSelection() const +{ + Q_D(const TransactionEditor); + return d->m_transactions.count() > 1; +} + bool TransactionEditor::fixTransactionCommodity(const MyMoneyAccount& account) { + Q_D(TransactionEditor); bool rc = true; bool firstTimeMultiCurrency = true; - m_account = account; + d->m_account = account; - MyMoneyFile* file = MyMoneyFile::instance(); + auto file = MyMoneyFile::instance(); // determine the max fraction for this account - MyMoneySecurity sec = file->security(m_account.currencyId()); - int fract = m_account.fraction(); + MyMoneySecurity sec = file->security(d->m_account.currencyId()); + int fract = d->m_account.fraction(); // scan the list of selected transactions KMyMoneyRegister::SelectedTransactions::iterator it_t; - for (it_t = m_transactions.begin(); (rc == true) && (it_t != m_transactions.end()); ++it_t) { + for (it_t = d->m_transactions.begin(); (rc == true) && (it_t != d->m_transactions.end()); ++it_t) { // there was a time when the schedule editor did not setup the transaction commodity // let's give a helping hand here for those old schedules if ((*it_t).transaction().commodity().isEmpty()) - (*it_t).transaction().setCommodity(m_account.currencyId()); + (*it_t).transaction().setCommodity(d->m_account.currencyId()); // we need to check things only if a different commodity is used - if (m_account.currencyId() != (*it_t).transaction().commodity()) { + if (d->m_account.currencyId() != (*it_t).transaction().commodity()) { MyMoneySecurity osec = file->security((*it_t).transaction().commodity()); switch ((*it_t).transaction().splitCount()) { case 0: // new transaction, guess nothing's here yet ;) break; case 1: try { // make sure, that the value is equal to the shares, don't forget our own copy MyMoneySplit& splitB = (*it_t).split(); // reference usage wanted here - if (m_split == splitB) - m_split.setValue(splitB.shares()); + if (d->m_split == splitB) + d->m_split.setValue(splitB.shares()); splitB.setValue(splitB.shares()); (*it_t).transaction().modifySplit(splitB); } catch (const MyMoneyException &e) { qDebug("Unable to update commodity to second splits currency in %s: '%s'", qPrintable((*it_t).transaction().id()), qPrintable(e.what())); } break; case 2: // If we deal with multiple currencies we make sure, that for // transactions with two splits, the transaction's commodity is the // currency of the currently selected account. This saves us from a // lot of grieve later on. We just have to switch the // transactions commodity. Let's assume the following scenario: // - transactions commodity is CA // - splitB and account's currencyId is CB // - splitA is of course in CA (otherwise we have a real problem) // - Value is V in both splits // - Shares in splitB is SB // - Shares in splitA is SA (and equal to V) // // We do the following: // - change transactions commodity to CB // - set V in both splits to SB // - modify the splits in the transaction try { // retrieve the splits MyMoneySplit& splitB = (*it_t).split(); // reference usage wanted here - MyMoneySplit splitA = (*it_t).transaction().splitByAccount(m_account.id(), false); + MyMoneySplit splitA = (*it_t).transaction().splitByAccount(d->m_account.id(), false); // - set V in both splits to SB. Don't forget our own copy - if (m_split == splitB) { - m_split.setValue(splitB.shares()); + if (d->m_split == splitB) { + d->m_split.setValue(splitB.shares()); } splitB.setValue(splitB.shares()); splitA.setValue(-splitB.shares()); (*it_t).transaction().modifySplit(splitA); (*it_t).transaction().modifySplit(splitB); } catch (const MyMoneyException &e) { qDebug("Unable to update commodity to second splits currency in %s: '%s'", qPrintable((*it_t).transaction().id()), qPrintable(e.what())); } break; default: // TODO: use new logic by adjusting all splits by the price // extracted from the selected split. Inform the user that // this will happen and allow him to stop the processing (rc = false) try { QString msg; if (firstTimeMultiCurrency) { firstTimeMultiCurrency = false; if (!isMultiSelection()) { msg = i18n("This transaction has more than two splits and is originally based on a different currency (%1). Using this account to modify the transaction may result in rounding errors. Do you want to continue?", osec.name()); } else { msg = i18n("At least one of the selected transactions has more than two splits and is originally based on a different currency (%1). Using this account to modify the transactions may result in rounding errors. Do you want to continue?", osec.name()); } if (KMessageBox::warningContinueCancel(0, QString("%1").arg(msg)) == KMessageBox::Cancel) { rc = false; } } if (rc == true) { MyMoneyMoney price; if (!(*it_t).split().shares().isZero() && !(*it_t).split().value().isZero()) price = (*it_t).split().shares() / (*it_t).split().value(); QList::iterator it_s; MyMoneySplit& mySplit = (*it_t).split(); for (it_s = (*it_t).transaction().splits().begin(); it_s != (*it_t).transaction().splits().end(); ++it_s) { MyMoneySplit s = (*it_s); if (s == mySplit) { s.setValue(s.shares()); - if (mySplit == m_split) { - m_split = s; + if (mySplit == d->m_split) { + d->m_split = s; } mySplit = s; } else { s.setValue((s.value() * price).convert(fract)); } (*it_t).transaction().modifySplit(s); } } } catch (const MyMoneyException &e) { qDebug("Unable to update commodity of split currency in %s: '%s'", qPrintable((*it_t).transaction().id()), qPrintable(e.what())); } break; } // set the transaction's ommodity to this account's currency - (*it_t).transaction().setCommodity(m_account.currencyId()); + (*it_t).transaction().setCommodity(d->m_account.currencyId()); // update our copy of the transaction that has the focus - if ((*it_t).transaction().id() == m_transaction.id()) { - m_transaction = (*it_t).transaction(); + if ((*it_t).transaction().id() == d->m_transaction.id()) { + d->m_transaction = (*it_t).transaction(); } } } return rc; } void TransactionEditor::assignNextNumber() { + Q_D(TransactionEditor); if (canAssignNumber()) { kMyMoneyLineEdit* number = dynamic_cast(haveWidget("number")); - QString num = KMyMoneyUtils::nextCheckNumber(m_account); + QString num = KMyMoneyUtils::nextCheckNumber(d->m_account); bool showMessage = true; int rc = KMessageBox::No; QString schedInfo; - if (!m_scheduleInfo.isEmpty()) { - schedInfo = i18n("
Processing schedule for %1.
", m_scheduleInfo); + if (!d->m_scheduleInfo.isEmpty()) { + schedInfo = i18n("
Processing schedule for %1.
", d->m_scheduleInfo); } - while (MyMoneyFile::instance()->checkNoUsed(m_account.id(), num)) { + while (MyMoneyFile::instance()->checkNoUsed(d->m_account.id(), num)) { if (showMessage) { - rc = KMessageBox::questionYesNo(m_regForm, QString("") + schedInfo + i18n("Check number %1 has already been used in account %2." - "
Do you want to replace it with the next available number?
", num, m_account.name()) + QString("
"), i18n("Duplicate number")); + rc = KMessageBox::questionYesNo(d->m_regForm, QString("") + schedInfo + i18n("Check number %1 has already been used in account %2." + "
Do you want to replace it with the next available number?
", num, d->m_account.name()) + QString("
"), i18n("Duplicate number")); showMessage = false; } if (rc == KMessageBox::Yes) { - num = KMyMoneyUtils::nextCheckNumber(m_account); - KMyMoneyUtils::updateLastNumberUsed(m_account, num); - m_account.setValue("lastNumberUsed", num); + num = KMyMoneyUtils::nextCheckNumber(d->m_account); + KMyMoneyUtils::updateLastNumberUsed(d->m_account, num); + d->m_account.setValue("lastNumberUsed", num); number->loadText(num); } else { num = QString(); break; } } number->setText(num); } } bool TransactionEditor::canAssignNumber() const { - kMyMoneyLineEdit* number = dynamic_cast(haveWidget("number")); + auto number = dynamic_cast(haveWidget("number")); return (number != 0); } void TransactionEditor::setupCategoryWidget(KMyMoneyCategory* category, const QList& splits, QString& categoryId, const char* splitEditSlot, bool /* allowObjectCreation */) { disconnect(category, SIGNAL(focusIn()), this, splitEditSlot); #if 0 // FIXME must deal with the logic that suppressObjectCreation is // automatically turned off when the createItem() signal is connected if (allowObjectCreation) category->setSuppressObjectCreation(false); #endif switch (splits.count()) { case 0: categoryId.clear(); if (!category->currentText().isEmpty()) { // category->clearEditText(); // don't clear as could be from another widget - Bug 322768 // make sure, we don't see the selector category->completion()->hide(); } category->completion()->setSelected(QString()); break; case 1: categoryId = splits[0].accountId(); category->completion()->setSelected(categoryId); category->slotItemSelected(categoryId); break; default: categoryId.clear(); category->setSplitTransaction(); connect(category, SIGNAL(focusIn()), this, splitEditSlot); #if 0 // FIXME must deal with the logic that suppressObjectCreation is // automatically turned off when the createItem() signal is connected if (allowObjectCreation) category->setSuppressObjectCreation(true); #endif break; } } bool TransactionEditor::enterTransactions(QString& newId, bool askForSchedule, bool suppressBalanceWarnings) { + Q_D(TransactionEditor); newId.clear(); - MyMoneyFile* file = MyMoneyFile::instance(); + auto file = MyMoneyFile::instance(); // make sure to run through all stuff that is tied to 'focusout events'. - m_regForm->parentWidget()->setFocus(); + d->m_regForm->parentWidget()->setFocus(); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 10); // we don't need to update our widgets anymore, so we just disconnect the signal - disconnect(file, SIGNAL(dataChanged()), this, SLOT(slotReloadEditWidgets())); + disconnect(file, &MyMoneyFile::dataChanged, this, &TransactionEditor::slotReloadEditWidgets); KMyMoneyRegister::SelectedTransactions::iterator it_t; MyMoneyTransaction t; bool newTransactionCreated = false; // make sure, that only a single new transaction can be created. // we need to update m_transactions to contain the new transaction // which is then stored in the variable t when we leave the loop. // m_transactions will be sent out in finishEdit() and forces // the new transaction to be selected in the ledger view // collect the transactions to be stored in the engine in a local // list first, so that the user has a chance to interrupt the storage // process QList list; - bool storeTransactions = true; + auto storeTransactions = true; // collect transactions - for (it_t = m_transactions.begin(); storeTransactions && !newTransactionCreated && it_t != m_transactions.end(); ++it_t) { + for (it_t = d->m_transactions.begin(); storeTransactions && !newTransactionCreated && it_t != d->m_transactions.end(); ++it_t) { storeTransactions = createTransaction(t, (*it_t).transaction(), (*it_t).split()); // if the transaction was created successfully, append it to the list if (storeTransactions) list.append(t); // if we created a new transaction keep that in mind if (t.id().isEmpty()) newTransactionCreated = true; } // if not interrupted by user, continue to store them in the engine if (storeTransactions) { - int i = 0; + auto i = 0; emit statusMsg(i18n("Storing transactions")); emit statusProgress(0, list.count()); MyMoneyFileTransaction ft; try { QList::iterator it_ts; QMap minBalanceEarly; QMap minBalanceAbsolute; QMap maxCreditEarly; QMap maxCreditAbsolute; QMap accountIds; for (it_ts = list.begin(); it_ts != list.end(); ++it_ts) { // if we have a categorization, make sure we remove // the 'imported' flag automagically if ((*it_ts).splitCount() > 1) (*it_ts).setImported(false); // create information about min and max balances QList::const_iterator it_s; for (it_s = (*it_ts).splits().constBegin(); it_s != (*it_ts).splits().constEnd(); ++it_s) { MyMoneyAccount acc = file->account((*it_s).accountId()); accountIds[acc.id()] = true; MyMoneyMoney balance = file->balance(acc.id()); if (!acc.value("minBalanceEarly").isEmpty()) { minBalanceEarly[acc.id()] = balance < MyMoneyMoney(acc.value("minBalanceEarly")); } if (!acc.value("minBalanceAbsolute").isEmpty()) { minBalanceAbsolute[acc.id()] = balance < MyMoneyMoney(acc.value("minBalanceAbsolute")); minBalanceEarly[acc.id()] = false; } if (!acc.value("maxCreditEarly").isEmpty()) { maxCreditEarly[acc.id()] = balance < MyMoneyMoney(acc.value("maxCreditEarly")); } if (!acc.value("maxCreditAbsolute").isEmpty()) { maxCreditAbsolute[acc.id()] = balance < MyMoneyMoney(acc.value("maxCreditAbsolute")); maxCreditEarly[acc.id()] = false; } } if ((*it_ts).id().isEmpty()) { bool enter = true; if (askForSchedule && (*it_ts).postDate() > QDate::currentDate()) { KGuiItem enterButton(i18n("&Enter"), QIcon::fromTheme(g_Icons[Icon::DialogOK]), i18n("Accepts the entered data and stores it"), i18n("Use this to enter the transaction into the ledger.")); KGuiItem scheduleButton(i18n("&Schedule"), QIcon::fromTheme(g_Icons[Icon::AppointmentNew]), i18n("Accepts the entered data and stores it as schedule"), i18n("Use this to schedule the transaction for later entry into the ledger.")); - enter = KMessageBox::questionYesNo(m_regForm, QString("%1").arg(i18n("The transaction you are about to enter has a post date in the future.

Do you want to enter it in the ledger or add it to the schedules?")), i18nc("Dialog caption for 'Enter or schedule' dialog", "Enter or schedule?"), enterButton, scheduleButton, "EnterOrScheduleTransactionInFuture") == KMessageBox::Yes; + enter = KMessageBox::questionYesNo(d->m_regForm, QString("%1").arg(i18n("The transaction you are about to enter has a post date in the future.

Do you want to enter it in the ledger or add it to the schedules?")), i18nc("Dialog caption for 'Enter or schedule' dialog", "Enter or schedule?"), enterButton, scheduleButton, "EnterOrScheduleTransactionInFuture") == KMessageBox::Yes; } if (enter) { // add new transaction file->addTransaction(*it_ts); // pass the newly assigned id on to the caller newId = (*it_ts).id(); // refresh account object for transactional changes // refresh account and transaction object because they might have changed - m_account = file->account(m_account.id()); + d->m_account = file->account(d->m_account.id()); t = (*it_ts); // if a new transaction has a valid number, keep it with the account - keepNewNumber((*it_ts)); + d->keepNewNumber((*it_ts)); } else { // turn object creation on, so that moving the focus does // not screw up the dialog that might be popping up emit objectCreation(true); emit scheduleTransaction(*it_ts, eMyMoney::Schedule::Occurrence::Once); emit objectCreation(false); newTransactionCreated = false; } // send out the post date of this transaction emit lastPostDateUsed((*it_ts).postDate()); } else { // modify existing transaction // its number might have been edited // bearing in mind it could contain alpha characters - keepNewNumber((*it_ts)); + d->keepNewNumber((*it_ts)); file->modifyTransaction(*it_ts); } } emit statusProgress(i++, 0); // update m_transactions to contain the newly created transaction so that // it is selected as the current one // we need to do that before we commit the transaction to the engine // as we need it during the update of the views that is caused by committing already. if (newTransactionCreated) { - m_transactions.clear(); + d->m_transactions.clear(); MyMoneySplit s; // a transaction w/o a single split should not exist and adding it // should throw an exception in MyMoneyFile::addTransaction, but we // remain on the save side of things to check for it if (t.splitCount() > 0) s = t.splits().front(); KMyMoneyRegister::SelectedTransaction st(t, s); - m_transactions.append(st); + d->m_transactions.append(st); } // Save pricing information QList::const_iterator it_t; for (it_t = t.splits().constBegin(); it_t != t.splits().constEnd(); ++it_t) { if (((*it_t).action() != "Buy") && ((*it_t).action() != "Reinvest")) { continue; } QString id = (*it_t).accountId(); MyMoneyAccount acc = file->account(id); MyMoneySecurity sec = file->security(acc.currencyId()); MyMoneyPrice price(acc.currencyId(), sec.tradingCurrency(), t.postDate(), (*it_t).price(), "Transaction"); file->addPrice(price); break; } ft.commit(); // now analyze the balances and spit out warnings to the user QMap::const_iterator it_a; if (!suppressBalanceWarnings) { for (it_a = accountIds.constBegin(); it_a != accountIds.constEnd(); ++it_a) { QString msg; MyMoneyAccount acc = file->account(it_a.key()); MyMoneyMoney balance = file->balance(acc.id()); const MyMoneySecurity& sec = file->security(acc.currencyId()); QString key; key = "minBalanceEarly"; if (!acc.value(key).isEmpty()) { if (minBalanceEarly[acc.id()] == false && balance < MyMoneyMoney(acc.value(key))) { msg = QString("%1").arg(i18n("The balance of account %1 dropped below the warning balance of %2.", acc.name(), MyMoneyUtils::formatMoney(MyMoneyMoney(acc.value(key)), acc, sec))); } } key = "minBalanceAbsolute"; if (!acc.value(key).isEmpty()) { if (minBalanceAbsolute[acc.id()] == false && balance < MyMoneyMoney(acc.value(key))) { msg = QString("%1").arg(i18n("The balance of account %1 dropped below the minimum balance of %2.", acc.name(), MyMoneyUtils::formatMoney(MyMoneyMoney(acc.value(key)), acc, sec))); } } key = "maxCreditEarly"; if (!acc.value(key).isEmpty()) { if (maxCreditEarly[acc.id()] == false && balance < MyMoneyMoney(acc.value(key))) { msg = QString("%1").arg(i18n("The balance of account %1 dropped below the maximum credit warning limit of %2.", acc.name(), MyMoneyUtils::formatMoney(MyMoneyMoney(acc.value(key)), acc, sec))); } } key = "maxCreditAbsolute"; if (!acc.value(key).isEmpty()) { if (maxCreditAbsolute[acc.id()] == false && balance < MyMoneyMoney(acc.value(key))) { msg = QString("%1").arg(i18n("The balance of account %1 dropped below the maximum credit limit of %2.", acc.name(), MyMoneyUtils::formatMoney(MyMoneyMoney(acc.value(key)), acc, sec))); } } if (!msg.isEmpty()) { - emit balanceWarning(m_regForm, acc, msg); + emit balanceWarning(d->m_regForm, acc, msg); } } } } catch (const MyMoneyException &e) { qDebug("Unable to store transaction within engine: %s", qPrintable(e.what())); newTransactionCreated = false; } emit statusProgress(-1, -1); emit statusMsg(QString()); } return storeTransactions; } -void TransactionEditor::keepNewNumber(const MyMoneyTransaction& tr) -{ - // verify that new number, possibly containing alpha, is valid - MyMoneyTransaction txn = tr; - MyMoneyFile* file = MyMoneyFile::instance(); - if (!txn.splits().isEmpty()) { - QString number = txn.splits().first().number(); - if (KMyMoneyUtils::numericPart(number) > 0) { - // numeric is valid - kMyMoneyLineEdit* numberEdit = dynamic_cast(haveWidget("number")); - if (numberEdit) { - numberEdit->loadText(number); - MyMoneySplit split = txn.splits().first(); - split.setNumber(number); - txn.modifySplit(split); - m_account.setValue("lastNumberUsed", number); - file->modifyAccount(m_account); - } - } - } -} - void TransactionEditor::resizeForm() { + Q_D(TransactionEditor); // force resizeing of the columns in the form - KMyMoneyTransactionForm::TransactionForm* form = dynamic_cast(m_regForm); + auto form = dynamic_cast(d->m_regForm); if (form) { QMetaObject::invokeMethod(form, "resize", Qt::QueuedConnection, QGenericReturnArgument(), Q_ARG(int, ValueColumn1)); } } - -StdTransactionEditor::StdTransactionEditor() : - m_inUpdateVat(false) -{ -} - -StdTransactionEditor::StdTransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::Transaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate) : - TransactionEditor(regForm, item, list, lastPostDate), - m_inUpdateVat(false) -{ -} - -StdTransactionEditor::~StdTransactionEditor() -{ -} - - -void StdTransactionEditor::createEditWidgets() -{ - // we only create the account widget in case it is needed - // to avoid confusion in the tab order later on. - if (m_item->showRowInForm(0)) { - KMyMoneyCategory* account = new KMyMoneyCategory; - account->setPlaceholderText(i18n("Account")); - account->setObjectName(QLatin1String("Account")); - m_editWidgets["account"] = account; - connect(account, SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(account, SIGNAL(itemSelected(QString)), this, SLOT(slotUpdateAccount(QString))); - } - - KMyMoneyPayeeCombo* payee = new KMyMoneyPayeeCombo; - payee->setPlaceholderText(i18n("Payer/Receiver")); - payee->setObjectName(QLatin1String("Payee")); - m_editWidgets["payee"] = payee; - - connect(payee, SIGNAL(createItem(QString,QString&)), this, SIGNAL(createPayee(QString,QString&))); - connect(payee, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); - connect(payee, SIGNAL(itemSelected(QString)), this, SLOT(slotUpdatePayee(QString))); - connect(payee, SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateButtonState())); - - KMyMoneyCategory* category = new KMyMoneyCategory(0, true); - category->setPlaceholderText(i18n("Category/Account")); - category->setObjectName(QLatin1String("Category/Account")); - m_editWidgets["category"] = category; - connect(category, SIGNAL(itemSelected(QString)), this, SLOT(slotUpdateCategory(QString))); - connect(category, SIGNAL(editTextChanged(QString)), this, SLOT(slotUpdateButtonState())); - connect(category, SIGNAL(createItem(QString,QString&)), this, SLOT(slotCreateCategory(QString,QString&))); - connect(category, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); - connect(category->splitButton(), SIGNAL(clicked()), this, SLOT(slotEditSplits())); - // initially disable the split button since we don't have an account set - if (category->splitButton()) - category->splitButton()->setDisabled(m_account.id().isEmpty()); - - KTagContainer* tag = new KTagContainer; - tag->tagCombo()->setPlaceholderText(i18n("Tag")); - tag->tagCombo()->setObjectName(QLatin1String("Tag")); - m_editWidgets["tag"] = tag; - connect(tag->tagCombo(), SIGNAL(createItem(QString,QString&)), this, SIGNAL(createTag(QString,QString&))); - connect(tag->tagCombo(), SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); - - KTextEdit* memo = new KTextEdit; - memo->setObjectName(QLatin1String("Memo")); - memo->setTabChangesFocus(true); - connect(memo, SIGNAL(textChanged()), this, SLOT(slotUpdateMemoState())); - connect(memo, SIGNAL(textChanged()), this, SLOT(slotUpdateButtonState())); - m_editWidgets["memo"] = memo; - m_memoText.clear(); - m_memoChanged = false; - - bool showNumberField = true; - switch (m_account.accountType()) { - case eMyMoney::Account::Savings: - case eMyMoney::Account::Cash: - case eMyMoney::Account::Loan: - case eMyMoney::Account::AssetLoan: - case eMyMoney::Account::Asset: - case eMyMoney::Account::Liability: - case eMyMoney::Account::Equity: - showNumberField = KMyMoneyGlobalSettings::alwaysShowNrField(); - break; - - case eMyMoney::Account::Income: - case eMyMoney::Account::Expense: - showNumberField = false; - break; - - default: - break; - } - - if (showNumberField) { - kMyMoneyLineEdit* number = new kMyMoneyLineEdit; - number->setPlaceholderText(i18n("Number")); - number->setObjectName(QLatin1String("Number")); - m_editWidgets["number"] = number; - connect(number, SIGNAL(lineChanged(QString)), this, SLOT(slotNumberChanged(QString))); - // number->installEventFilter(this); - } - - kMyMoneyDateInput* postDate = new kMyMoneyDateInput; - m_editWidgets["postdate"] = postDate; - postDate->setObjectName(QLatin1String("PostDate")); - connect(postDate, SIGNAL(dateChanged(QDate)), this, SLOT(slotUpdateButtonState())); - postDate->setDate(QDate()); - - kMyMoneyEdit* value = new kMyMoneyEdit; - m_editWidgets["amount"] = value; - value->setObjectName(QLatin1String("Amount")); - value->setResetButtonVisible(false); - connect(value, SIGNAL(valueChanged(QString)), this, SLOT(slotUpdateAmount(QString))); - connect(value, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateButtonState())); - - value = new kMyMoneyEdit; - m_editWidgets["payment"] = value; - value->setObjectName(QLatin1String("Payment")); - value->setResetButtonVisible(false); - connect(value, SIGNAL(valueChanged(QString)), this, SLOT(slotUpdatePayment(QString))); - connect(value, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateButtonState())); - - value = new kMyMoneyEdit; - m_editWidgets["deposit"] = value; - value->setObjectName(QLatin1String("Deposit")); - value->setResetButtonVisible(false); - connect(value, SIGNAL(valueChanged(QString)), this, SLOT(slotUpdateDeposit(QString))); - connect(value, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateButtonState())); - - KMyMoneyCashFlowCombo* cashflow = new KMyMoneyCashFlowCombo(0, m_account.accountGroup()); - m_editWidgets["cashflow"] = cashflow; - cashflow->setObjectName(QLatin1String("Cashflow")); - connect(cashflow, SIGNAL(directionSelected(KMyMoneyRegister::CashFlowDirection)), this, SLOT(slotUpdateCashFlow(KMyMoneyRegister::CashFlowDirection))); - - KMyMoneyReconcileCombo* reconcile = new KMyMoneyReconcileCombo; - m_editWidgets["status"] = reconcile; - reconcile->setObjectName(QLatin1String("Reconcile")); - - KMyMoneyRegister::QWidgetContainer::iterator it_w; - for (it_w = m_editWidgets.begin(); it_w != m_editWidgets.end(); ++it_w) { - (*it_w)->installEventFilter(this); - } - // if we don't have more than 1 selected transaction, we don't need - // the "don't change" item in some of the combo widgets - if (!isMultiSelection()) { - reconcile->removeDontCare(); - cashflow->removeDontCare(); - } - - QLabel* label; - m_editWidgets["account-label"] = label = new QLabel(i18n("Account")); - label->setAlignment(Qt::AlignVCenter); - - m_editWidgets["category-label"] = label = new QLabel(i18n("Category")); - label->setAlignment(Qt::AlignVCenter); - - m_editWidgets["tag-label"] = label = new QLabel(i18n("Tags")); - label->setAlignment(Qt::AlignVCenter); - - m_editWidgets["memo-label"] = label = new QLabel(i18n("Memo")); - label->setAlignment(Qt::AlignVCenter); - - m_editWidgets["number-label"] = label = new QLabel(i18n("Number")); - label->setAlignment(Qt::AlignVCenter); - - m_editWidgets["date-label"] = label = new QLabel(i18n("Date")); - label->setAlignment(Qt::AlignVCenter); - - m_editWidgets["amount-label"] = label = new QLabel(i18n("Amount")); - label->setAlignment(Qt::AlignVCenter); - - m_editWidgets["status-label"] = label = new QLabel(i18n("Status")); - label->setAlignment(Qt::AlignVCenter); - - // create a copy of tabbar above the form (if we are created for a form) - KMyMoneyTransactionForm::TransactionForm* form = dynamic_cast(m_regForm); - if (form) { - KMyMoneyTransactionForm::TabBar* tabbar = new KMyMoneyTransactionForm::TabBar; - m_editWidgets["tabbar"] = tabbar; - tabbar->setObjectName(QLatin1String("TabBar")); - tabbar->copyTabs(form->tabBar()); - connect(tabbar, SIGNAL(tabCurrentChanged(int)), this, SLOT(slotUpdateAction(int))); - connect(tabbar, SIGNAL(tabCurrentChanged(int)), this, SIGNAL(operationTypeChanged(int))); - } - - setupPrecision(); -} - -void StdTransactionEditor::setupCategoryWidget(QString& categoryId) -{ - TransactionEditor::setupCategoryWidget(dynamic_cast(m_editWidgets["category"]), m_splits, categoryId, SLOT(slotEditSplits())); - - if (m_splits.count() == 1) - m_shares = m_splits[0].shares(); -} - -bool StdTransactionEditor::isTransfer(const QString& accId1, const QString& accId2) const -{ - if (accId1.isEmpty() || accId2.isEmpty()) - return false; - - return MyMoneyFile::instance()->account(accId1).isIncomeExpense() == MyMoneyFile::instance()->account(accId2).isIncomeExpense(); -} - -void StdTransactionEditor::loadEditWidgets(KMyMoneyRegister::Action action) -{ - // don't kick off VAT processing from here - m_inUpdateVat = true; - - QMap::const_iterator it_w; - QWidget* w; - AccountSet aSet; - - // load the account widget - KMyMoneyCategory* account = dynamic_cast(haveWidget("account")); - if (account) { - aSet.addAccountGroup(eMyMoney::Account::Asset); - aSet.addAccountGroup(eMyMoney::Account::Liability); - aSet.removeAccountType(eMyMoney::Account::AssetLoan); - aSet.removeAccountType(eMyMoney::Account::CertificateDep); - aSet.removeAccountType(eMyMoney::Account::Investment); - aSet.removeAccountType(eMyMoney::Account::Stock); - aSet.removeAccountType(eMyMoney::Account::MoneyMarket); - aSet.removeAccountType(eMyMoney::Account::Loan); - aSet.load(account->selector()); - account->completion()->setSelected(m_account.id()); - account->slotItemSelected(m_account.id()); - } - - // load the payee widget - KMyMoneyPayeeCombo* payee = dynamic_cast(m_editWidgets["payee"]); - payee->loadPayees(MyMoneyFile::instance()->payeeList()); - - // load the category widget - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); - disconnect(category, SIGNAL(focusIn()), this, SLOT(slotEditSplits())); - - // load the tag widget - //KMyMoneyTagCombo* tag = dynamic_cast(m_editWidgets["tag"]); - KTagContainer* tag = dynamic_cast(m_editWidgets["tag"]); - tag->loadTags(MyMoneyFile::instance()->tagList()); - - // check if the current transaction has a reference to an equity account - bool haveEquityAccount = false; - QList::const_iterator it_s; - for (it_s = m_transaction.splits().constBegin(); !haveEquityAccount && it_s != m_transaction.splits().constEnd(); ++it_s) { - MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId()); - if (acc.accountType() == eMyMoney::Account::Equity) - haveEquityAccount = true; - } - - aSet.clear(); - aSet.addAccountGroup(eMyMoney::Account::Asset); - aSet.addAccountGroup(eMyMoney::Account::Liability); - aSet.addAccountGroup(eMyMoney::Account::Income); - aSet.addAccountGroup(eMyMoney::Account::Expense); - if (KMyMoneyGlobalSettings::expertMode() || haveEquityAccount) - aSet.addAccountGroup(eMyMoney::Account::Equity); - - aSet.removeAccountType(eMyMoney::Account::CertificateDep); - aSet.removeAccountType(eMyMoney::Account::Investment); - aSet.removeAccountType(eMyMoney::Account::Stock); - aSet.removeAccountType(eMyMoney::Account::MoneyMarket); - aSet.load(category->selector()); - - // if an account is specified then remove it from the widget so that the user - // cannot create a transfer with from and to account being the same account - if (!m_account.id().isEmpty()) - category->selector()->removeItem(m_account.id()); - - // also show memo text if isMultiSelection() - dynamic_cast(m_editWidgets["memo"])->setText(m_split.memo()); - // need to know if it changed - m_memoText = m_split.memo(); - m_memoChanged = false; - - if (!isMultiSelection()) { - if (m_transaction.postDate().isValid()) - dynamic_cast(m_editWidgets["postdate"])->setDate(m_transaction.postDate()); - else if (m_lastPostDate.isValid()) - dynamic_cast(m_editWidgets["postdate"])->setDate(m_lastPostDate); - else - dynamic_cast(m_editWidgets["postdate"])->setDate(QDate::currentDate()); - - if ((w = haveWidget("number")) != 0) { - dynamic_cast(w)->loadText(m_split.number()); - if (m_transaction.id().isEmpty() // new transaction - && dynamic_cast(w)->text().isEmpty() // no number filled in - && m_account.accountType() == eMyMoney::Account::Checkings // checkings account - && KMyMoneyGlobalSettings::autoIncCheckNumber() // and auto inc number turned on? - && action != KMyMoneyRegister::ActionDeposit // only transfers or withdrawals - && m_paymentMethod == eMyMoney::Schedule::PaymentType::WriteChecque) {// only for WriteChecque - assignNextNumber(); - } - } - dynamic_cast(m_editWidgets["status"])->setState(m_split.reconcileFlag()); - - QString payeeId = m_split.payeeId(); - if (!payeeId.isEmpty()) { - payee->setSelectedItem(payeeId); - } - QList t = m_split.tagIdList(); - if (!t.isEmpty()) { - for (int i = 0; i < t.size(); i++) - tag->addTagWidget(t[i]); - } - - m_splits.clear(); - if (m_transaction.splitCount() < 2) { - category->completion()->setSelected(QString()); - } else { - QList::const_iterator it_s; - for (it_s = m_transaction.splits().constBegin(); it_s != m_transaction.splits().constEnd(); ++it_s) { - if ((*it_s) == m_split) - continue; - m_splits.append(*it_s); - } - } - QString categoryId; - setupCategoryWidget(categoryId); - - if ((w = haveWidget("cashflow")) != 0) { - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(w); - cashflow->setDirection(!m_split.value().isPositive() ? KMyMoneyRegister::Payment : KMyMoneyRegister::Deposit); // include isZero case - } - - if ((w = haveWidget("category-label")) != 0) { - QLabel *categoryLabel = dynamic_cast(w); - if (isTransfer(m_split.accountId(), categoryId)) { - if (m_split.value().isPositive()) - categoryLabel->setText(i18n("Transfer from")); - else - categoryLabel->setText(i18n("Transfer to")); - } - } - - MyMoneyMoney value = m_split.shares(); - - if (haveWidget("deposit")) { - if (m_split.shares().isNegative()) { - dynamic_cast(m_editWidgets["deposit"])->loadText(""); - dynamic_cast(m_editWidgets["payment"])->setValue(value.abs()); - } else { - dynamic_cast(m_editWidgets["deposit"])->setValue(value.abs()); - dynamic_cast(m_editWidgets["payment"])->loadText(""); - } - } - if ((w = haveWidget("amount")) != 0) { - dynamic_cast(w)->setValue(value.abs()); - } - - slotUpdateCategory(categoryId); - - // try to preset for specific action if a new transaction is being started - if (m_transaction.id().isEmpty()) { - if ((w = haveWidget("category-label")) != 0) { - TabBar* tabbar = dynamic_cast(haveWidget("tabbar")); - if (action == KMyMoneyRegister::ActionNone) { - if (tabbar) { - action = static_cast(tabbar->currentIndex()); - } - } - if (action != KMyMoneyRegister::ActionNone) { - QLabel *categoryLabel = dynamic_cast(w); - if (action == KMyMoneyRegister::ActionTransfer) { - if (m_split.value().isPositive()) - categoryLabel->setText(i18n("Transfer from")); - else - categoryLabel->setText(i18n("Transfer to")); - } - if ((w = haveWidget("cashflow")) != 0) { - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(w); - if (action == KMyMoneyRegister::ActionDeposit || (action == KMyMoneyRegister::ActionTransfer && m_split.value().isPositive())) - cashflow->setDirection(KMyMoneyRegister::Deposit); - else - cashflow->setDirection(KMyMoneyRegister::Payment); - } - if (tabbar) { - tabbar->setCurrentIndex(action); - } - } - } - } else { - TabBar* tabbar = dynamic_cast(haveWidget("tabbar")); - if (tabbar) { - if (!isTransfer(m_split.accountId(), categoryId)) { - tabbar->setCurrentIndex(m_split.value().isNegative() ? KMyMoneyRegister::ActionWithdrawal : KMyMoneyRegister::ActionDeposit); - } else { - tabbar->setCurrentIndex(KMyMoneyRegister::ActionTransfer); - } - } - } - - } else { // isMultiSelection() - dynamic_cast(m_editWidgets["postdate"])->loadDate(QDate()); - dynamic_cast(m_editWidgets["status"])->setState(eMyMoney::Split::State::Unknown); - if (haveWidget("deposit")) { - dynamic_cast(m_editWidgets["deposit"])->loadText(""); - dynamic_cast(m_editWidgets["deposit"])->setAllowEmpty(); - dynamic_cast(m_editWidgets["payment"])->loadText(""); - dynamic_cast(m_editWidgets["payment"])->setAllowEmpty(); - } - if ((w = haveWidget("amount")) != 0) { - dynamic_cast(w)->loadText(""); - dynamic_cast(w)->setAllowEmpty(); - } - - slotUpdateAction(action); - - if ((w = haveWidget("tabbar")) != 0) { - w->setEnabled(false); - } - - category->completion()->setSelected(QString()); - } - - // allow kick off VAT processing again - m_inUpdateVat = false; -} - -QWidget* StdTransactionEditor::firstWidget() const -{ - QWidget* w = 0; - if (m_initialAction != KMyMoneyRegister::ActionNone) { - w = haveWidget("payee"); - } - return w; -} - -void StdTransactionEditor::slotReloadEditWidgets() -{ - // reload category widget - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); - QString categoryId = category->selectedItem(); - - AccountSet aSet; - aSet.addAccountGroup(eMyMoney::Account::Asset); - aSet.addAccountGroup(eMyMoney::Account::Liability); - aSet.addAccountGroup(eMyMoney::Account::Income); - aSet.addAccountGroup(eMyMoney::Account::Expense); - if (KMyMoneyGlobalSettings::expertMode()) - aSet.addAccountGroup(eMyMoney::Account::Equity); - aSet.load(category->selector()); - - // if an account is specified then remove it from the widget so that the user - // cannot create a transfer with from and to account being the same account - if (!m_account.id().isEmpty()) - category->selector()->removeItem(m_account.id()); - - if (!categoryId.isEmpty()) - category->setSelectedItem(categoryId); - - - // reload payee widget - KMyMoneyPayeeCombo* payee = dynamic_cast(m_editWidgets["payee"]); - QString payeeId = payee->selectedItem(); - - payee->loadPayees(MyMoneyFile::instance()->payeeList()); - - if (!payeeId.isEmpty()) { - payee->setSelectedItem(payeeId); - } - - // reload tag widget - KTagContainer* tag = dynamic_cast(m_editWidgets["tag"]); - QString tagId = tag->tagCombo()->selectedItem(); - - tag->loadTags(MyMoneyFile::instance()->tagList()); - - if (!tagId.isEmpty()) { - tag->RemoveAllTagWidgets(); - tag->addTagWidget(tagId); - } -} - -void StdTransactionEditor::slotUpdatePayee(const QString& payeeId) -{ - // we have a new payee assigned to this transaction. - // in case there is no category assigned, no value entered and no - // memo available, we search for the last transaction of this payee - // in the account. - if (m_transaction.id().isEmpty() - && m_splits.count() == 0 - && KMyMoneyGlobalSettings::autoFillTransaction() != 0) { - // check if category is empty - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); - QStringList list; - category->selectedItems(list); - if (!list.isEmpty()) - return; - - // check if memo is empty - KTextEdit* memo = dynamic_cast(m_editWidgets["memo"]); - if (memo && !memo->toPlainText().isEmpty()) - return; - - // check if all value fields are empty - kMyMoneyEdit* amount; - QStringList fields; - fields << "amount" << "payment" << "deposit"; - QStringList::const_iterator it_f; - for (it_f = fields.constBegin(); it_f != fields.constEnd(); ++it_f) { - amount = dynamic_cast(haveWidget(*it_f)); - if (amount && !amount->value().isZero()) - return; - } - -#if 0 - // Tony mentioned, that autofill does not work when he changed the date. Well, - // that certainly makes sense when you enter transactions in register mode as - // opposed to form mode, because the date field is located prior to the date - // field in the tab order of the widgets and the user might have already - // changed it. - // - // So I commented out the code that checks the date but left it in for reference. - // (ipwizard, 2008-04-07) - - // check if date has been altered by user - kMyMoneyDateInput* postDate = dynamic_cast(m_editWidgets["postdate"]); - if ((m_lastPostDate.isValid() && (postDate->date() != m_lastPostDate)) - || (!m_lastPostDate.isValid() && (postDate->date() != QDate::currentDate()))) - return; -#endif - - // if we got here, we have to autofill - autoFill(payeeId); - } - - // If payee has associated default account (category), set that now. - const MyMoneyPayee& payeeObj = MyMoneyFile::instance()->payee(payeeId); - if (payeeObj.defaultAccountEnabled()) { - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); - category->slotItemSelected(payeeObj.defaultAccountId()); - } -} - -MyMoneyMoney StdTransactionEditor::shares(const MyMoneyTransaction& t) const -{ - MyMoneyMoney result; - QList::const_iterator it_s; - for (it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) { - if ((*it_s).accountId() == m_account.id()) { - result += (*it_s).shares(); - } - } - return result; -} - -struct uniqTransaction { - const MyMoneyTransaction* t; - int cnt; -}; - -void StdTransactionEditor::autoFill(const QString& payeeId) -{ - QList > list; - MyMoneyTransactionFilter filter(m_account.id()); - filter.addPayee(payeeId); - MyMoneyFile::instance()->transactionList(list, filter); - if (!list.empty()) { - // ok, we found at least one previous transaction. now we clear out - // what we have collected so far and add those splits from - // the previous transaction. - QList >::const_iterator it_t; - QMap uniqList; - - // collect the transactions and see if we have any duplicates - for (it_t = list.constBegin(); it_t != list.constEnd(); ++it_t) { - QString key = (*it_t).first.accountSignature(); - int cnt = 0; - QMap::iterator it_u; - do { - QString ukey = QString("%1-%2").arg(key).arg(cnt); - it_u = uniqList.find(ukey); - if (it_u == uniqList.end()) { - uniqList[ukey].t = &((*it_t).first); - uniqList[ukey].cnt = 1; - } else if (KMyMoneyGlobalSettings::autoFillTransaction() == 1) { - // we already have a transaction with this signature. we must - // now check, if we should really treat it as a duplicate according - // to the value comparison delta. - MyMoneyMoney s1 = shares(*((*it_u).t)); - MyMoneyMoney s2 = shares((*it_t).first); - if (s2.abs() > s1.abs()) { - MyMoneyMoney t(s1); - s1 = s2; - s2 = t; - } - MyMoneyMoney diff; - if (s2.isZero()) - diff = s1.abs(); - else - diff = ((s1 - s2) / s2).convert(10000); - if (diff.isPositive() && diff <= MyMoneyMoney(KMyMoneyGlobalSettings::autoFillDifference(), 100)) { - uniqList[ukey].t = &((*it_t).first); - break; // end while loop - } - } else if (KMyMoneyGlobalSettings::autoFillTransaction() == 2) { - (*it_u).cnt++; - break; // end while loop - } - ++cnt; - } while (it_u != uniqList.end()); - - } - - MyMoneyTransaction t; - if (KMyMoneyGlobalSettings::autoFillTransaction() != 2) { -#if 0 - // I removed this code to allow cancellation of an autofill if - // it does not match even if there is only a single matching - // transaction for the payee in question. In case, we want to revert - // to the old behavior, don't forget to uncomment the closing - // brace further down in the code as well. (ipwizard 2009-01-16) - if (uniqList.count() == 1) { - t = list.last().first; - } else { -#endif - QPointer dlg = new KSelectTransactionsDlg(m_account, m_regForm); - dlg->setWindowTitle(i18n("Select autofill transaction")); - - QMap::const_iterator it_u; - for (it_u = uniqList.constBegin(); it_u != uniqList.constEnd(); ++it_u) { - dlg->addTransaction(*(*it_u).t); - } - - // setup sort order - dlg->m_register->setSortOrder("1,-9,-4"); - // sort the transactions according to the sort setting - dlg->m_register->sortItems(); - - // and select the last item - if (dlg->m_register->lastItem()) - dlg->m_register->selectItem(dlg->m_register->lastItem()); - - if (dlg->exec() == QDialog::Accepted) { - t = dlg->transaction(); - } -#if 0 - } -#endif - } else { - int maxCnt = 0; - QMap::const_iterator it_u; - for (it_u = uniqList.constBegin(); it_u != uniqList.constEnd(); ++it_u) { - if ((*it_u).cnt > maxCnt) { - t = *(*it_u).t; - maxCnt = (*it_u).cnt; - } - } - } - - if (t != MyMoneyTransaction()) { - m_transaction.removeSplits(); - m_split = MyMoneySplit(); - MyMoneySplit otherSplit; - QList::ConstIterator it; - for (it = t.splits().constBegin(); it != t.splits().constEnd(); ++it) { - MyMoneySplit s(*it); - s.setReconcileFlag(eMyMoney::Split::State::NotReconciled); - s.setReconcileDate(QDate()); - s.clearId(); - s.setBankID(QString()); - // older versions of KMyMoney used to set the action - // we don't need this anymore - if (s.action() != MyMoneySplit::ActionAmortization - && s.action() != MyMoneySplit::ActionInterest) { - s.setAction(QString()); - } - - // FIXME update check number. The old comment contained - // - // - // If a check number is already specified by the user it is - // used. If the input field is empty and the previous transaction - // contains a checknumber, the next usable check number will be assigned - // to the transaction. - // - - kMyMoneyLineEdit* editNr = dynamic_cast(haveWidget("number")); - if (editNr && !editNr->text().isEmpty()) { - s.setNumber(editNr->text()); - } else if (!s.number().isEmpty()) { - s.setNumber(KMyMoneyUtils::nextCheckNumber(m_account)); - } - - // if the memos should not be used with autofill or - // if the transaction has exactly two splits, remove - // the memo text of the split that does not reference - // the current account. This allows the user to change - // the autofilled memo text which will then also be used - // in this split. See createTransaction() for this logic. - if ((s.accountId() != m_account.id() && t.splitCount() == 2) || !KMyMoneyGlobalSettings::autoFillUseMemos()) - s.setMemo(QString()); - - m_transaction.addSplit(s); - if (s.accountId() == m_account.id() && m_split == MyMoneySplit()) { - m_split = s; - } else { - otherSplit = s; - } - } - - // make sure to extract the right action - KMyMoneyRegister::Action action; - action = m_split.shares().isNegative() ? KMyMoneyRegister::ActionWithdrawal : KMyMoneyRegister::ActionDeposit; - - if (m_transaction.splitCount() == 2) { - MyMoneyAccount acc = MyMoneyFile::instance()->account(otherSplit.accountId()); - if (acc.isAssetLiability()) - action = KMyMoneyRegister::ActionTransfer; - } - - // now setup the widgets with the new data but keep the date - QDate date = dynamic_cast(m_editWidgets["postdate"])->date(); - loadEditWidgets(action); - dynamic_cast(m_editWidgets["postdate"])->setDate(date); - } - } - - // focus jumps into the category field - QWidget* w; - if ((w = haveWidget("payee")) != 0) { - w->setFocus(); - } -} - -void StdTransactionEditor::slotUpdateAction(int action) -{ - TabBar* tabbar = dynamic_cast(haveWidget("tabbar")); - if (tabbar) { - QLabel* categoryLabel = dynamic_cast(haveWidget("category-label")); - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(m_editWidgets["cashflow"]); - switch (action) { - case KMyMoneyRegister::ActionDeposit: - categoryLabel->setText(i18n("Category")); - cashflow->setDirection(KMyMoneyRegister::Deposit); - break; - case KMyMoneyRegister::ActionTransfer: - if (m_split.shares().isNegative()) { - cashflow->setDirection(KMyMoneyRegister::Payment); - categoryLabel->setText(i18n("Transfer to")); - } else { - cashflow->setDirection(KMyMoneyRegister::Deposit); - categoryLabel->setText(i18n("Transfer from")); - } - tabbar->setCurrentIndex(KMyMoneyRegister::ActionTransfer); - slotUpdateCashFlow(cashflow->direction()); - break; - case KMyMoneyRegister::ActionWithdrawal: - categoryLabel->setText(i18n("Category")); - cashflow->setDirection(KMyMoneyRegister::Payment); - break; - } - resizeForm(); - } -} - -void StdTransactionEditor::slotUpdateCashFlow(KMyMoneyRegister::CashFlowDirection dir) -{ - QLabel* categoryLabel = dynamic_cast(haveWidget("category-label")); - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(haveWidget("cashflow")); - cashflow->setDirection(dir); - // qDebug("Update cashflow to %d", dir); - if (categoryLabel) { - TabBar* tabbar = dynamic_cast(haveWidget("tabbar")); - if (!tabbar) return; // no transaction form - if (categoryLabel->text() != i18n("Category")) { - tabbar->setCurrentIndex(KMyMoneyRegister::ActionTransfer); - if (dir == KMyMoneyRegister::Deposit) { - categoryLabel->setText(i18n("Transfer from")); - } else { - categoryLabel->setText(i18n("Transfer to")); - } - resizeForm(); - } else { - if (dir == KMyMoneyRegister::Deposit) - tabbar->setCurrentIndex(KMyMoneyRegister::ActionDeposit); - else - tabbar->setCurrentIndex(KMyMoneyRegister::ActionWithdrawal); - } - } -} - -void StdTransactionEditor::slotUpdateCategory(const QString& id) -{ - QLabel *categoryLabel = dynamic_cast(haveWidget("category-label")); - // qDebug("Update category to %s", qPrintable(id)); - - if (categoryLabel) { - TabBar* tabbar = dynamic_cast(haveWidget("tabbar")); - kMyMoneyEdit* amount = dynamic_cast(m_editWidgets["amount"]); - MyMoneyMoney val = amount->value(); - - if (categoryLabel->text() == i18n("Transfer from")) { - val = -val; - } else { - val = val.abs(); - } - - if (tabbar) { - tabbar->setTabEnabled(KMyMoneyRegister::ActionTransfer, true); - tabbar->setTabEnabled(KMyMoneyRegister::ActionDeposit, true); - tabbar->setTabEnabled(KMyMoneyRegister::ActionWithdrawal, true); - } - - bool disableTransferTab = false; - if (!id.isEmpty()) { - MyMoneyAccount acc = MyMoneyFile::instance()->account(id); - if (acc.isAssetLiability() - || acc.accountGroup() == eMyMoney::Account::Equity) { - if (tabbar) { - tabbar->setCurrentIndex(KMyMoneyRegister::ActionTransfer); - tabbar->setTabEnabled(KMyMoneyRegister::ActionDeposit, false); - tabbar->setTabEnabled(KMyMoneyRegister::ActionWithdrawal, false); - } - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(m_editWidgets["cashflow"]); - if (val.isZero()) { - if (cashflow && (cashflow->direction() == KMyMoneyRegister::Deposit)) { - categoryLabel->setText(i18n("Transfer from")); - } else { - categoryLabel->setText(i18n("Transfer to")); - } - } else if (val.isNegative()) { - categoryLabel->setText(i18n("Transfer from")); - cashflow->setDirection(KMyMoneyRegister::Deposit); - } else - categoryLabel->setText(i18n("Transfer to")); - } else { - disableTransferTab = true; - categoryLabel->setText(i18n("Category")); - } - updateAmount(val); - } else { //id.isEmpty() - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); - disableTransferTab = !category->currentText().isEmpty(); - categoryLabel->setText(i18n("Category")); - } - if (tabbar) { - if (disableTransferTab) { - // set the proper tab before disabling the currently active tab - if (tabbar->currentIndex() == KMyMoneyRegister::ActionTransfer) { - tabbar->setCurrentIndex(val.isPositive() ? KMyMoneyRegister::ActionWithdrawal : KMyMoneyRegister::ActionDeposit); - } - tabbar->setTabEnabled(KMyMoneyRegister::ActionTransfer, false); - } - tabbar->update(); - } - - resizeForm(); - } - updateVAT(false); -} - -void StdTransactionEditor::slotUpdatePayment(const QString& txt) -{ - MyMoneyMoney val(txt); - - if (val.isNegative()) { - dynamic_cast(m_editWidgets["deposit"])->setValue(val.abs()); - dynamic_cast(m_editWidgets["payment"])->clearText(); - } else { - dynamic_cast(m_editWidgets["deposit"])->clearText(); - } - updateVAT(); -} - -void StdTransactionEditor::slotUpdateDeposit(const QString& txt) -{ - MyMoneyMoney val(txt); - if (val.isNegative()) { - dynamic_cast(m_editWidgets["payment"])->setValue(val.abs()); - dynamic_cast(m_editWidgets["deposit"])->clearText(); - } else { - dynamic_cast(m_editWidgets["payment"])->clearText(); - } - updateVAT(); -} - -void StdTransactionEditor::slotUpdateAmount(const QString& txt) -{ - // qDebug("Update amount to %s", qPrintable(txt)); - MyMoneyMoney val(txt); - updateAmount(val); - updateVAT(true); -} - -void StdTransactionEditor::updateAmount(const MyMoneyMoney& val) -{ - // we don't do anything if we have multiple transactions selected - if (isMultiSelection()) - return; - - QLabel *categoryLabel = dynamic_cast(haveWidget("category-label")); - if (categoryLabel) { - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(m_editWidgets["cashflow"]); - - if (!val.isPositive()) { // fixes BUG321317 - if (categoryLabel->text() != i18n("Category")) { - if (cashflow->direction() == KMyMoneyRegister::Payment) { - categoryLabel->setText(i18n("Transfer to")); - } - } else { - slotUpdateCashFlow(cashflow->direction()); - } - dynamic_cast(m_editWidgets["amount"])->setValue(val.abs()); - } else { - if (categoryLabel->text() != i18n("Category")) { - if (cashflow->direction() == KMyMoneyRegister::Payment) { - categoryLabel->setText(i18n("Transfer to")); - } else { - categoryLabel->setText(i18n("Transfer from")); - cashflow->setDirection(KMyMoneyRegister::Deposit); // editing with +ve shows 'from' not 'pay to' - } - } - dynamic_cast(m_editWidgets["amount"])->setValue(val.abs()); - } - } -} - -void StdTransactionEditor::updateVAT(bool amountChanged) -{ - // make sure that we don't do this recursively - if (m_inUpdateVat) - return; - - // we don't do anything if we have multiple transactions selected - if (isMultiSelection()) - return; - - // if auto vat assignment for this account is turned off - // we don't care about taxes - if (m_account.value("NoVat") == "Yes") - return; - - // more splits than category and tax are not supported - if (m_splits.count() > 2) - return; - - // in order to do anything, we need an amount - MyMoneyMoney amount, newAmount; - bool amountOk; - amount = amountFromWidget(&amountOk); - if (!amountOk) - return; - - // If the transaction has a tax and a category split, remove the tax split - if (m_splits.count() == 2) { - newAmount = removeVatSplit(); - if (m_splits.count() == 2) // not removed? - return; - - } else { - // otherwise, we need a category - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); - if (category->selectedItem().isEmpty()) - return; - - // if no VAT account is associated with this category/account, then we bail out - MyMoneyAccount cat = MyMoneyFile::instance()->account(category->selectedItem()); - if (cat.value("VatAccount").isEmpty()) - return; - - newAmount = amount; - } - - // seems we have everything we need - if (amountChanged) - newAmount = amount; - - MyMoneyTransaction transaction; - if (createTransaction(transaction, m_transaction, m_split)) { - if (addVatSplit(transaction, newAmount)) { - m_transaction = transaction; - if (!m_transaction.splits().isEmpty()) - m_split = m_transaction.splits().front(); - - loadEditWidgets(); - - // if we made this a split transaction, then move the - // focus to the memo field - if (qApp->focusWidget() == haveWidget("category")) { - QWidget* w = haveWidget("memo"); - if (w) - w->setFocus(); - } - } - } -} - -bool StdTransactionEditor::addVatSplit(MyMoneyTransaction& tr, const MyMoneyMoney& amount) -{ - if (tr.splitCount() != 2) - return false; - - MyMoneyFile* file = MyMoneyFile::instance(); - // extract the category split from the transaction - MyMoneyAccount category = file->account(tr.splitByAccount(m_account.id(), false).accountId()); - return file->addVATSplit(tr, m_account, category, amount); -} - -MyMoneyMoney StdTransactionEditor::removeVatSplit() -{ - // we only deal with splits that have three splits - if (m_splits.count() != 2) - return amountFromWidget(); - - MyMoneySplit c; // category split - MyMoneySplit t; // tax split - - bool netValue = false; - QList::const_iterator it_s; - for (it_s = m_splits.constBegin(); it_s != m_splits.constEnd(); ++it_s) { - MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId()); - if (!acc.value("VatAccount").isEmpty()) { - netValue = (acc.value("VatAmount").toLower() == "net"); - c = (*it_s); - } else if (!acc.value("VatRate").isEmpty()) { - t = (*it_s); - } - } - - // bail out if not all splits are setup - if (c.id().isEmpty() || t.id().isEmpty()) - return amountFromWidget(); - - MyMoneyMoney amount; - // reduce the splits - if (netValue) { - amount = -c.shares(); - } else { - amount = -(c.shares() + t.shares()); - } - - // remove tax split from the list, ... - m_splits.clear(); - m_splits.append(c); - - // ... make sure that the widget is updated ... - // block the signals to avoid popping up the split editor dialog - // for nothing - m_editWidgets["category"]->blockSignals(true); - QString id; - setupCategoryWidget(id); - m_editWidgets["category"]->blockSignals(false); - - // ... and return the updated amount - return amount; -} - -bool StdTransactionEditor::isComplete(QString& reason) const -{ - reason.clear(); - QMap::const_iterator it_w; - - kMyMoneyDateInput* postDate = dynamic_cast(m_editWidgets["postdate"]); - if (postDate) { - QDate accountOpeningDate = m_account.openingDate(); - for (QList::const_iterator it_s = m_splits.constBegin(); it_s != m_splits.constEnd(); ++it_s) { - const MyMoneyAccount& acc = MyMoneyFile::instance()->account((*it_s).accountId()); - // compute the newest opening date of all accounts involved in the transaction - if (acc.openingDate() > accountOpeningDate) - accountOpeningDate = acc.openingDate(); - } - // check the selected category in case m_splits hasn't been updated yet - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); - if (category && !category->selectedItem().isEmpty()) { - MyMoneyAccount cat = MyMoneyFile::instance()->account(category->selectedItem()); - if (cat.openingDate() > accountOpeningDate) - accountOpeningDate = cat.openingDate(); - } - - if (postDate->date().isValid() && (postDate->date() < accountOpeningDate)) { - postDate->markAsBadDate(true, KMyMoneyGlobalSettings::schemeColor(SchemeColor::Negative)); - reason = i18n("Cannot enter transaction with postdate prior to account's opening date."); - postDate->setToolTip(reason); - return false; - } - postDate->markAsBadDate(); - postDate->setToolTip(""); - } - - for (it_w = m_editWidgets.begin(); it_w != m_editWidgets.end(); ++it_w) { - KMyMoneyPayeeCombo* payee = dynamic_cast(*it_w); - KTagContainer* tagContainer = dynamic_cast(*it_w); - KMyMoneyCategory* category = dynamic_cast(*it_w); - kMyMoneyEdit* amount = dynamic_cast(*it_w); - KMyMoneyReconcileCombo* reconcile = dynamic_cast(*it_w); - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(*it_w); - KTextEdit* memo = dynamic_cast(*it_w); - - if (payee && !(payee->currentText().isEmpty())) - break; - - if (category && !category->lineEdit()->text().isEmpty()) - break; - - if (amount && !(amount->value().isZero())) - break; - - // the following widgets are only checked if we are editing multiple transactions - if (isMultiSelection()) { - TabBar* tabbar = dynamic_cast(haveWidget("tabbar")); - if (tabbar) { - tabbar->setEnabled(true); - } - if (reconcile && reconcile->state() != eMyMoney::Split::State::Unknown) - break; - - if (cashflow && cashflow->direction() != KMyMoneyRegister::Unknown) - break; - - if (postDate->date().isValid() && (postDate->date() >= m_account.openingDate())) - break; - - if (memo && m_memoChanged) - break; - - if (tagContainer && !(tagContainer->selectedTags().isEmpty())) // Tag is optional field - break; - } - } - return it_w != m_editWidgets.end(); -} - -void StdTransactionEditor::slotCreateCategory(const QString& name, QString& id) -{ - MyMoneyAccount acc, parent; - acc.setName(name); - - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(haveWidget("cashflow")); - if (cashflow) { - // form based input - if (cashflow->direction() == KMyMoneyRegister::Deposit) - parent = MyMoneyFile::instance()->income(); - else - parent = MyMoneyFile::instance()->expense(); - - } else if (haveWidget("deposit")) { - // register based input - kMyMoneyEdit* deposit = dynamic_cast(m_editWidgets["deposit"]); - if (deposit->value().isPositive()) - parent = MyMoneyFile::instance()->income(); - else - parent = MyMoneyFile::instance()->expense(); - - } else - parent = MyMoneyFile::instance()->expense(); - - // TODO extract possible first part of a hierarchy and check if it is one - // of our top categories. If so, remove it and select the parent - // according to this information. - - emit createCategory(acc, parent); - - // return id - id = acc.id(); -} - -int StdTransactionEditor::slotEditSplits() -{ - int rc = QDialog::Rejected; - - if (!m_openEditSplits) { - // only get in here in a single instance - m_openEditSplits = true; - - // force focus change to update all data - QWidget* w = dynamic_cast(m_editWidgets["category"])->splitButton(); - if (w) - w->setFocus(); - - kMyMoneyEdit* amount = dynamic_cast(haveWidget("amount")); - kMyMoneyEdit* deposit = dynamic_cast(haveWidget("deposit")); - kMyMoneyEdit* payment = dynamic_cast(haveWidget("payment")); - KMyMoneyCashFlowCombo* cashflow = 0; - KMyMoneyRegister::CashFlowDirection dir = KMyMoneyRegister::Unknown; - bool isValidAmount = false; - - if (amount) { - isValidAmount = amount->lineedit()->text().length() != 0; - cashflow = dynamic_cast(haveWidget("cashflow")); - if (cashflow) - dir = cashflow->direction(); - - } else { - if (deposit) { - if (deposit->lineedit()->text().length() != 0) { - isValidAmount = true; - dir = KMyMoneyRegister::Deposit; - } - } - if (payment) { - if (payment->lineedit()->text().length() != 0) { - isValidAmount = true; - dir = KMyMoneyRegister::Payment; - } - } - if (!deposit || !payment) { - qDebug("Internal error: deposit(%p) & payment(%p) widgets not found but required", deposit, payment); - return rc; - } - } - - if (dir == KMyMoneyRegister::Unknown) - dir = KMyMoneyRegister::Payment; - - MyMoneyTransaction transaction; - if (createTransaction(transaction, m_transaction, m_split)) { - MyMoneyMoney value; - - QPointer dlg = - new KSplitTransactionDlg(transaction, - transaction.splits().isEmpty() ? MyMoneySplit() : transaction.splits().front(), - m_account, - isValidAmount, - dir == KMyMoneyRegister::Deposit, - MyMoneyMoney(), - m_priceInfo, - m_regForm); - connect(dlg, SIGNAL(objectCreation(bool)), this, SIGNAL(objectCreation(bool))); - connect(dlg, SIGNAL(createCategory(MyMoneyAccount&,MyMoneyAccount)), this, SIGNAL(createCategory(MyMoneyAccount&,MyMoneyAccount))); - - if ((rc = dlg->exec()) == QDialog::Accepted) { - m_transaction = dlg->transaction(); - if (!m_transaction.splits().isEmpty()) - m_split = m_transaction.splits().front(); - loadEditWidgets(); - } - - delete dlg; - } - - // focus jumps into the tag field - if ((w = haveWidget("tag")) != 0) { - w->setFocus(); - } - - m_openEditSplits = false; - } - - return rc; -} - -void StdTransactionEditor::checkPayeeInSplit(MyMoneySplit& s, const QString& payeeId) -{ - if (s.accountId().isEmpty()) - return; - - MyMoneyAccount acc = MyMoneyFile::instance()->account(s.accountId()); - if (acc.isIncomeExpense()) { - s.setPayeeId(payeeId); - } else { - if (s.payeeId().isEmpty()) - s.setPayeeId(payeeId); - } -} - -MyMoneyMoney StdTransactionEditor::amountFromWidget(bool* update) const -{ - bool updateValue = false; - MyMoneyMoney value; - - KMyMoneyCashFlowCombo* cashflow = dynamic_cast(haveWidget("cashflow")); - if (cashflow) { - // form based input - kMyMoneyEdit* amount = dynamic_cast(m_editWidgets["amount"]); - // if both fields do not contain changes -> no need to update - if (cashflow->direction() != KMyMoneyRegister::Unknown - && !amount->lineedit()->text().isEmpty()) - updateValue = true; - value = amount->value(); - if (cashflow->direction() == KMyMoneyRegister::Payment) - value = -value; - - } else if (haveWidget("deposit")) { - // register based input - kMyMoneyEdit* deposit = dynamic_cast(m_editWidgets["deposit"]); - kMyMoneyEdit* payment = dynamic_cast(m_editWidgets["payment"]); - // if both fields do not contain text -> no need to update - if (!(deposit->lineedit()->text().isEmpty() && payment->lineedit()->text().isEmpty())) - updateValue = true; - - if (deposit->value().isPositive()) - value = deposit->value(); - else - value = -(payment->value()); - } - - if (update) - *update = updateValue; - - // determine the max fraction for this account and - // adjust the value accordingly - return value.convert(m_account.fraction()); -} - -bool StdTransactionEditor::createTransaction(MyMoneyTransaction& t, const MyMoneyTransaction& torig, const MyMoneySplit& sorig, bool skipPriceDialog) -{ - // extract price info from original transaction - m_priceInfo.clear(); - QList::const_iterator it_s; - if (!torig.id().isEmpty()) { - for (it_s = torig.splits().begin(); it_s != torig.splits().end(); ++it_s) { - if ((*it_s).id() != sorig.id()) { - MyMoneyAccount cat = MyMoneyFile::instance()->account((*it_s).accountId()); - if (cat.currencyId() != m_account.currencyId()) { - if (!(*it_s).shares().isZero() && !(*it_s).value().isZero()) { - m_priceInfo[cat.currencyId()] = ((*it_s).shares() / (*it_s).value()).reduce(); - } - } - } - } - } - - t = torig; - - t.removeSplits(); - t.setCommodity(m_account.currencyId()); - - kMyMoneyDateInput* postDate = dynamic_cast(m_editWidgets["postdate"]); - if (postDate->date().isValid()) { - t.setPostDate(postDate->date()); - } - - // we start with the previous values, make sure we can add them later on - MyMoneySplit s0 = sorig; - s0.clearId(); - - // make sure we reference this account here - s0.setAccountId(m_account.id()); - - // memo and number field are special: if we have multiple transactions selected - // and the edit field is empty, we treat it as "not modified". - // FIXME a better approach would be to have a 'dirty' flag with the widgets - // which identifies if the originally loaded value has been modified - // by the user - KTextEdit* memo = dynamic_cast(m_editWidgets["memo"]); - if (memo) { - if (!isMultiSelection() || (isMultiSelection() && m_memoChanged)) - s0.setMemo(memo->toPlainText()); - } - - kMyMoneyLineEdit* number = dynamic_cast(haveWidget("number")); - if (number) { - if (!isMultiSelection() || (isMultiSelection() && !number->text().isEmpty())) - s0.setNumber(number->text()); - } - - KMyMoneyPayeeCombo* payee = dynamic_cast(m_editWidgets["payee"]); - QString payeeId; - if (!isMultiSelection() || (isMultiSelection() && !payee->currentText().isEmpty())) { - payeeId = payee->selectedItem(); - s0.setPayeeId(payeeId); - } - - //KMyMoneyTagCombo* tag = dynamic_cast(m_editWidgets["tag"]); - KTagContainer* tag = dynamic_cast(m_editWidgets["tag"]); - if (!isMultiSelection() || (isMultiSelection() && !tag->selectedTags().isEmpty())) { - s0.setTagIdList(tag->selectedTags()); - } - - bool updateValue; - MyMoneyMoney value = amountFromWidget(&updateValue); - - if (updateValue) { - // for this account, the shares and value is the same - s0.setValue(value); - s0.setShares(value); - } else { - value = s0.value(); - } - - // if we mark the split reconciled here, we'll use today's date if no reconciliation date is given - KMyMoneyReconcileCombo* status = dynamic_cast(m_editWidgets["status"]); - if (status->state() != eMyMoney::Split::State::Unknown) - s0.setReconcileFlag(status->state()); - - if (s0.reconcileFlag() == eMyMoney::Split::State::Reconciled && !s0.reconcileDate().isValid()) - s0.setReconcileDate(QDate::currentDate()); - - checkPayeeInSplit(s0, payeeId); - - // add the split to the transaction - t.addSplit(s0); - - // if we have no other split we create it - // if we have none or only one other split, we reconstruct it here - // if we have more than one other split, we take them as they are - // make sure to perform all those changes on a local copy - QList splits = m_splits; - - MyMoneySplit s1; - if (splits.isEmpty()) { - s1.setMemo(s0.memo()); - splits.append(s1); - - // make sure we will fill the value and share fields later on - updateValue = true; - } - - // FIXME in multiSelection we currently only support transactions with one - // or two splits. So we check the original transaction and extract the other - // split or create it - if (isMultiSelection()) { - if (torig.splitCount() == 2) { - QList::const_iterator it_s; - for (it_s = torig.splits().begin(); it_s != torig.splits().end(); ++it_s) { - if ((*it_s).id() == sorig.id()) - continue; - s1 = *it_s; - s1.clearId(); - break; - } - } - } else { - if (splits.count() == 1) { - s1 = splits[0]; - s1.clearId(); - } - } - - if (isMultiSelection() || splits.count() == 1) { - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); - if (!isMultiSelection() || (isMultiSelection() && !category->currentText().isEmpty())) { - s1.setAccountId(category->selectedItem()); - } - - // if the first split has a memo but the second split is empty, - // we just copy the memo text over - if (memo) { - if (!isMultiSelection() || (isMultiSelection() && !memo->toPlainText().isEmpty())) { - // if the memo is filled, we check if the - // account referenced by s1 is a regular account or a category. - // in case of a regular account, we just leave the memo as is - // in case of a category we simply copy the new value over the old. - // in case we don't even have an account id, we just skip because - // the split will be removed later on anyway. - if (!s1.memo().isEmpty() && s1.memo() != s0.memo()) { - if (!s1.accountId().isEmpty()) { - MyMoneyAccount acc = MyMoneyFile::instance()->account(s1.accountId()); - if (acc.isIncomeExpense()) - s1.setMemo(s0.memo()); - else if (KMessageBox::questionYesNo(m_regForm, - i18n("Do you want to replace memo

%1

with memo

%2

in the other split?", s1.memo(), s0.memo()), i18n("Copy memo"), - KStandardGuiItem::yes(), KStandardGuiItem::no(), - QStringLiteral("CopyMemoOver")) == KMessageBox::Yes) - s1.setMemo(s0.memo()); - } - } else { - s1.setMemo(s0.memo()); - } - } - } - - if (updateValue && !s1.accountId().isEmpty()) { - s1.setValue(-value); - MyMoneyMoney shares; - if (!skipPriceDialog) { - if (!KCurrencyCalculator::setupSplitPrice(shares, t, s1, m_priceInfo, m_regForm)) - return false; - } else { - MyMoneyAccount cat = MyMoneyFile::instance()->account(s1.accountId()); - if (m_priceInfo.find(cat.currencyId()) != m_priceInfo.end()) { - shares = (s1.value() * m_priceInfo[cat.currencyId()]).reduce().convert(cat.fraction()); - } else - shares = s1.value(); - } - s1.setShares(shares); - } - - checkPayeeInSplit(s1, payeeId); - - if (!s1.accountId().isEmpty()) - t.addSplit(s1); - - } else { - QList::iterator it_s; - for (it_s = splits.begin(); it_s != splits.end(); ++it_s) { - s1 = *it_s; - s1.clearId(); - checkPayeeInSplit(s1, payeeId); - t.addSplit(s1); - } - } - return true; -} - -void StdTransactionEditor::setupFinalWidgets() -{ - addFinalWidget(haveWidget("deposit")); - addFinalWidget(haveWidget("payment")); - addFinalWidget(haveWidget("amount")); - addFinalWidget(haveWidget("status")); -} - -void StdTransactionEditor::slotUpdateAccount(const QString& id) -{ - TransactionEditor::slotUpdateAccount(id); - KMyMoneyCategory* category = dynamic_cast(m_editWidgets["category"]); - if (category && category->splitButton()) { - category->splitButton()->setDisabled(id.isEmpty()); - } -} diff --git a/kmymoney/dialogs/transactioneditor.h b/kmymoney/dialogs/transactioneditor.h index f63361173..b65c43c32 100644 --- a/kmymoney/dialogs/transactioneditor.h +++ b/kmymoney/dialogs/transactioneditor.h @@ -1,445 +1,327 @@ /*************************************************************************** transactioneditor.h ---------- begin : Wed Jun 07 2006 copyright : (C) 2006 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef TRANSACTIONEDITOR_H #define TRANSACTIONEDITOR_H // ---------------------------------------------------------------------------- // QT Includes #include +#include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes -#include "register.h" - -class QString; -class QWidget; -class QEvent; +class QDate; class TransactionEditorContainer; class KMyMoneyCategory; -class MyMoneySchedule; +class MyMoneySplit; +class MyMoneyTransaction; +class MyMoneyAccount; template class QList; +namespace KMyMoneyRegister { + enum Action : int; + class SelectedTransactions; + class Transaction; +} + +namespace eMyMoney { + namespace Schedule { enum class Occurrence; + enum class PaymentType; } + namespace Split { enum class InvestmentTransactionType; } + } + +class TransactionEditorPrivate; class TransactionEditor : public QObject { Q_OBJECT + Q_DISABLE_COPY(TransactionEditor) + public: TransactionEditor(); - TransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::Transaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate); + explicit TransactionEditor(TransactionEditorPrivate &dd, + TransactionEditorContainer* regForm, + KMyMoneyRegister::Transaction* item, + const KMyMoneyRegister::SelectedTransactions& list, + const QDate& lastPostDate); virtual ~TransactionEditor(); /** * This method is used as a helper because virtual methods cannot be * called within a constructor. Thus setup() should be called immediately * after a TransactionEditor() object or one of its derivatives is * constructed. The parameter @a account identifies the account that * is currently opened in the calling ledger view. * * This account will not be included in category sets. The default is * no account so all will be shown. I have no idea anymore, what I * tried to say with the first sentence above. :( Maybe this is crap. * * @param tabOrderWidgets QWidgetList which will be filled with the pointers * to the editWidgets in their tab order * @param account account that is currently shown in the calling ledger view * @param action default action (defaults to ActionNone). */ - void setup(QWidgetList& tabOrderWidgets, const MyMoneyAccount& account = MyMoneyAccount(), KMyMoneyRegister::Action action = KMyMoneyRegister::ActionNone); + void setup(QWidgetList& tabOrderWidgets, const MyMoneyAccount& account, KMyMoneyRegister::Action action); + void setup(QWidgetList& tabOrderWidgets, const MyMoneyAccount& account); + void setup(QWidgetList& tabOrderWidgets); /** * Enter the transactions into the ledger. In case of a newly created * transaction @a newId contains the assigned id. In case @a askForSchedule * is true (the default), the user will be asked if he wants to enter new * transactions with a post date in the future into the ledger or rather * create a schedule for them. In case @a suppressBalanceWarnings is @p false * (the default) a warning will be displayed when the balance crosses the minimum * or maximum balance settings for the account. */ virtual bool enterTransactions(QString& newId, bool askForSchedule = true, bool suppressBalanceWarnings = false); /** * This method creates a transaction based on the contents of the current widgets, * the splits in m_split in single selection mode or an existing transaction/split * and the contents of the widgets in multi selection mode. * * The split referencing the current account is returned as the first split in the * transaction's split list. * * @param t reference to created transaction * @param torig the original transaction * @param sorig the original split * @param skipPriceDialog if @p true the user will not be requested for price information * (defaults to @p false) * * @return @p false if aborted by user, @p true otherwise * * @note Usually not used directly. If unsure, use enterTransactions() instead. */ virtual bool createTransaction(MyMoneyTransaction& t, const MyMoneyTransaction& torig, const MyMoneySplit& sorig, bool skipPriceDialog = false) = 0; /** * This method returns information about the completeness of the data * entered. This can be used to control the availability of the * 'Enter transaction' action. * * @retval true if entering the transaction into the engine * @retval false if not enough information is present to enter the * transaction into the engine * * @param reason will be filled with a string about the reason why the * completeness is not reached. Empty if the return value * is @c true. * * @sa transactionDataSufficient() */ virtual bool isComplete(QString& reason) const = 0; /** * This method returns information if the editor is started with multiple transactions * being selected or not. * * @retval false only a single transaction was selected when the editor was started * @retval true multiple transactions were selected when the editor was started */ - virtual bool isMultiSelection() const { - return m_transactions.count() > 1; - } + virtual bool isMultiSelection() const; virtual bool fixTransactionCommodity(const MyMoneyAccount& account); virtual bool canAssignNumber() const; virtual void assignNextNumber(); /** * Returns a pointer to the widget that should receive * the focus after the editor has been started. */ virtual QWidget* firstWidget() const = 0; /** * Returns a pointer to a widget by name */ QWidget* haveWidget(const QString& name) const; void setTransaction(const MyMoneyTransaction& t, const MyMoneySplit& s); - bool eventFilter(QObject* o, QEvent* e); + bool eventFilter(QObject* o, QEvent* e) override; - const MyMoneyAccount& account() const { - return m_account; - } + MyMoneyAccount account() const; void clearFinalWidgets(); void addFinalWidget(const QWidget*); - QString m_memoText; - QString m_scheduleInfo; - - eMyMoney::Schedule::PaymentType m_paymentMethod; + void setScheduleInfo(const QString& si); + void setPaymentMethod(eMyMoney::Schedule::PaymentType pm); public slots: void slotReloadEditWidgets(); /** * The default implementation returns QDialog::Rejected */ virtual int slotEditSplits(); /** * Modify the account which the transaction should be based on. The * initial value for the account is passed during setup(). * * @param id of the account to be used */ virtual void slotUpdateAccount(const QString& id); protected: virtual void createEditWidgets() = 0; virtual void setupFinalWidgets() = 0; - virtual void loadEditWidgets(KMyMoneyRegister::Action action = KMyMoneyRegister::ActionNone) = 0; + virtual void loadEditWidgets(KMyMoneyRegister::Action action) = 0; + virtual void loadEditWidgets() = 0; void setupCategoryWidget(KMyMoneyCategory* category, const QList& splits, QString& categoryId, const char* splitEditSlot, bool allowObjectCreation = true); void resizeForm(); /** * This method sets the precision of the value widgets to reflect * the account in m_account. If m_account has no id, the precision * defaults to 2. */ void setupPrecision(); protected slots: void slotUpdateButtonState(); void slotUpdateMemoState(); void slotUpdateAccount(); void slotNumberChanged(const QString&); signals: /** * This signal is sent out by the destructor to inform other entities * that editing has been finished. The parameter @a t contains the list * of transactions that were processed. */ void finishEdit(const KMyMoneyRegister::SelectedTransactions& t); /** * This signal is sent out whenever enough data is present to enter the * transaction into the ledger. This signal can be used to control the * KAction which implements entering the transaction. * * @sa isComplete() * * @param state @a true if enough data is present, @a false otherwise. */ void transactionDataSufficient(bool state); /** * This signal is sent out, when a new payee needs to be created * @sa KMyMoneyCombo::createItem() * * @param txt The name of the payee to be created * @param id A connected slot should store the id of the created object in this variable */ - void createPayee(const QString& txt, QString& id); + bool createPayee(const QString& txt, QString& id); /** * This signal is sent out, when a new category needs to be created * Depending on the setting of either a payment or deposit, the parent * account will be preset to Expense or Income. * * @param account reference to account info. Will be filled by called slot * @param parent reference to parent account */ void createCategory(MyMoneyAccount& account, const MyMoneyAccount& parent); /** * This signal is sent out, when a new tag needs to be created * @param txt The name of the tag to be created * @param id A connected slot should store the id of the created object in this variable */ void createTag(const QString& txt, QString& id); /** * This signal is sent out, when a new security (e.g. stock )needs to be created * @a Parent should be the investment account under which the security account * will be created. * * @param account reference to account info. Will be filled by called slot * @param parent reference to parent account */ void createSecurity(MyMoneyAccount& account, const MyMoneyAccount& parent); /** * Signal is emitted, if any of the widgets enters (@a state equals @a true) * or leaves (@a state equals @a false) object creation mode. * * @param state Enter (@a true) or leave (@a false) object creation */ void objectCreation(bool state); void statusMsg(const QString& txt); void statusProgress(int cnt, int base); /** * This signal is sent out for each newly added transaction * * @param date the post date of the newly created transaction */ void lastPostDateUsed(const QDate& date); /** * This signal is sent out, if the user decides to schedule the transaction @a t * rather then adding it to the ledger right away. */ void scheduleTransaction(const MyMoneyTransaction& t, eMyMoney::Schedule::Occurrence occurrence); /** * This signal is sent out, if the user double clicks the number field */ void assignNumber(); /** * This signal is sent out, if the user has pressed the ESC key. */ - void escapePressed(); + void escapePressed(int msec = 100); /** * This signal is sent out, if the user has pressed the Return or Enter * key and asks to end editing the transaction */ - void returnPressed(); + void returnPressed(int msec = 100); /** * This signal is sent out, if any of the balance warning levels * for @p account has been reached. @p msg contains the message text. * @p parent points to the parent widget to be used for the warning message box. */ void balanceWarning(QWidget* parent, const MyMoneyAccount& account, const QString& msg); void operationTypeChanged(int index); protected: - QList m_splits; - KMyMoneyRegister::SelectedTransactions m_transactions; - QList m_finalEditWidgets; - TransactionEditorContainer* m_regForm; - KMyMoneyRegister::Transaction* m_item; - KMyMoneyRegister::QWidgetContainer m_editWidgets; - MyMoneyAccount m_account; - MyMoneyTransaction m_transaction; - MyMoneySplit m_split; - QDate m_lastPostDate; - QMap m_priceInfo; - KMyMoneyRegister::Action m_initialAction; - bool m_openEditSplits; - bool m_memoChanged; + QScopedPointer d_ptr; + TransactionEditor(TransactionEditorPrivate &dd); private: - /** - * If a new or an edited transaction has a valid number, keep it with the account - */ - void keepNewNumber(const MyMoneyTransaction& tr); - + Q_DECLARE_PRIVATE(TransactionEditor) }; -class StdTransactionEditor : public TransactionEditor -{ - Q_OBJECT -public: - StdTransactionEditor(); - StdTransactionEditor(TransactionEditorContainer* regForm, KMyMoneyRegister::Transaction* item, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate); - ~StdTransactionEditor(); - - bool isComplete(QString& reason) const; - QWidget* firstWidget() const; - - /** - * This method creates a transaction based on the contents of the current widgets, - * the splits in m_split in single selection mode or an existing transaction/split - * and the contents of the widgets in multi selection mode. - * - * The split referencing the current account is returned as the first split in the - * transaction's split list. - * - * @param t reference to created transaction - * @param torig the original transaction - * @param sorig the original split - * @param skipPriceDialog if @p true the user will not be requested for price information - * (defaults to @p false) - * - * @return @p false if aborted by user, @p true otherwise - * - * @note Usually not used directly. If unsure, use enterTransactions() instead. - */ - bool createTransaction(MyMoneyTransaction& t, const MyMoneyTransaction& torig, const MyMoneySplit& sorig, bool skipPriceDialog = false); - -public slots: - int slotEditSplits(); - void slotUpdateAmount(const QString&); - -protected slots: - void slotReloadEditWidgets(); - void slotUpdatePayment(const QString&); - void slotUpdateDeposit(const QString&); - void slotUpdateCategory(const QString&); - void slotUpdatePayee(const QString&); - //void slotUpdateTag(const QString&); - void slotUpdateCashFlow(KMyMoneyRegister::CashFlowDirection); - void slotCreateCategory(const QString&, QString&); - void slotUpdateAction(int action); - void slotUpdateAccount(const QString& id); - -protected: - /** - * This method creates all necessary widgets for this transaction editor. - * All signals will be connected to the relevant slots. - */ - void createEditWidgets(); - - /** - * This method (re-)loads the widgets with the transaction information - * contained in @a m_transaction and @a m_split. - * - * @param action preset the edit wigdets for @a action if no transaction - * is present - */ - void loadEditWidgets(KMyMoneyRegister::Action action = KMyMoneyRegister::ActionNone); - - void setupCategoryWidget(QString&); - void updateAmount(const MyMoneyMoney& value); - bool isTransfer(const QString& accId1, const QString& accId2) const; - - void checkPayeeInSplit(MyMoneySplit& s, const QString& payeeId); - - /** - * This method fills the editor widgets with the last transaction - * that can be found for payee @a payeeId in the account @a m_account. - */ - void autoFill(const QString& payeeId); - - /** - * Extracts the amount of the transaction from the widgets depending - * if form or register based input method is used. - * Returns if an amount has been found in @a update. - * - * @param update pointer to update information flag - * @return amount of transaction (deposit positive, payment negative) - */ - MyMoneyMoney amountFromWidget(bool* update = 0) const; - - /** - * Create or update a VAT split - */ - void updateVAT(bool amountChanged = true); - - MyMoneyMoney removeVatSplit(); - - /** - * This method adds a VAT split to transaction @a tr if necessary. - * - * @param tr transaction that the split should be added to - * @param amount Amount to be used for the calculation. Depending upon the - * setting of the resp. category, this value is treated as - * either gross or net value. - * @retval false VAT split has not been added - * @retval true VAT split has been added - */ - bool addVatSplit(MyMoneyTransaction& tr, const MyMoneyMoney& amount); - - void setupFinalWidgets(); - - /** - * This method returns the sum of all splits of transaction @a t that - * reference account m_account. - */ - MyMoneyMoney shares(const MyMoneyTransaction& t) const; - -private: - MyMoneyMoney m_shares; - bool m_inUpdateVat; -}; - - #endif diff --git a/kmymoney/dialogs/transactioneditor_p.h b/kmymoney/dialogs/transactioneditor_p.h new file mode 100644 index 000000000..3c6d35500 --- /dev/null +++ b/kmymoney/dialogs/transactioneditor_p.h @@ -0,0 +1,124 @@ +/*************************************************************************** + transactioneditor_p.h + ---------- + begin : Wed Jun 07 2006 + copyright : (C) 2006 by Thomas Baumgart + email : Thomas Baumgart + (C) 2017 by Ł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. * + * * + ***************************************************************************/ + +#ifndef TRANSACTIONEDITOR_P_H +#define TRANSACTIONEDITOR_P_H + +// ---------------------------------------------------------------------------- +// QT Includes + +#include +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- +// KDE Includes + +// ---------------------------------------------------------------------------- +// Project Includes + +#include "kmymoneylineedit.h" +#include "kmymoneyutils.h" +#include "mymoneyaccount.h" +#include "mymoneyenums.h" +#include "mymoneyfile.h" +#include "mymoneysplit.h" +#include "mymoneytransaction.h" +#include "register.h" +#include "registeritem.h" +#include "selectedtransaction.h" +#include "transactioneditor.h" + +class MyMoneyMoney; +class TransactionEditorContainer; +namespace KMyMoneyRegister { class Transaction; } + +class TransactionEditorPrivate +{ + Q_DISABLE_COPY(TransactionEditorPrivate) + Q_DECLARE_PUBLIC(TransactionEditor) + +public: + TransactionEditorPrivate(TransactionEditor *qq) : + q_ptr(qq) + { + } + + ~TransactionEditorPrivate() + { + } + + void init() + { + m_paymentMethod = eMyMoney::Schedule::PaymentType::Any; + m_regForm = 0; + m_item = 0; + m_initialAction = KMyMoneyRegister::ActionNone; + m_openEditSplits = false; + m_memoChanged = false; + } + + /** + * If a new or an edited transaction has a valid number, keep it with the account + */ + void keepNewNumber(const MyMoneyTransaction& tr) + { + Q_Q(TransactionEditor); + // verify that new number, possibly containing alpha, is valid + auto txn = tr; + auto file = MyMoneyFile::instance(); + if (!txn.splits().isEmpty()) { + QString number = txn.splits().first().number(); + if (KMyMoneyUtils::numericPart(number) > 0) { + // numeric is valid + auto numberEdit = dynamic_cast(q->haveWidget("number")); + if (numberEdit) { + numberEdit->loadText(number); + MyMoneySplit split = txn.splits().first(); + split.setNumber(number); + txn.modifySplit(split); + m_account.setValue("lastNumberUsed", number); + file->modifyAccount(m_account); + } + } + } + } + + TransactionEditor *q_ptr; + QString m_scheduleInfo; + eMyMoney::Schedule::PaymentType m_paymentMethod; + QString m_memoText; + QList m_splits; + KMyMoneyRegister::SelectedTransactions m_transactions; + QList m_finalEditWidgets; + TransactionEditorContainer* m_regForm; + KMyMoneyRegister::Transaction* m_item; + KMyMoneyRegister::QWidgetContainer m_editWidgets; + MyMoneyAccount m_account; + MyMoneyTransaction m_transaction; + MyMoneySplit m_split; + QDate m_lastPostDate; + QMap m_priceInfo; + KMyMoneyRegister::Action m_initialAction; + bool m_openEditSplits; + bool m_memoChanged; +}; + +#endif // KMERGETRANSACTIONSDLG_H diff --git a/kmymoney/dialogs/transactionmatcher.cpp b/kmymoney/dialogs/transactionmatcher.cpp index 07418f843..1dde5d059 100644 --- a/kmymoney/dialogs/transactionmatcher.cpp +++ b/kmymoney/dialogs/transactionmatcher.cpp @@ -1,198 +1,220 @@ /*************************************************************************** transactionmatcher.cpp ---------- begin : Tue Jul 08 2008 copyright : (C) 2008 by Thomas Baumgart email : Thomas Baumgart : Christian David + (C) 2017 by Ł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. * * * ***************************************************************************/ #include "transactionmatcher.h" -#include +#include + #include -#include +#include "mymoneyaccount.h" #include "mymoneymoney.h" #include "mymoneysplit.h" #include "mymoneytransaction.h" #include "mymoneyutils.h" #include "mymoneyfile.h" -#include "kmymoneyglobalsettings.h" #include "mymoneyexception.h" +class TransactionMatcherPrivate +{ + Q_DISABLE_COPY(TransactionMatcherPrivate) + +public: + TransactionMatcherPrivate() + { + } + + MyMoneyAccount m_account; +}; + TransactionMatcher::TransactionMatcher(const MyMoneyAccount& acc) : - m_account(acc) + d_ptr(new TransactionMatcherPrivate) +{ + Q_D(TransactionMatcher); + d->m_account = acc; +} + +TransactionMatcher::~TransactionMatcher() { + Q_D(TransactionMatcher); + delete d; } void TransactionMatcher::match(MyMoneyTransaction tm, MyMoneySplit sm, MyMoneyTransaction ti, MyMoneySplit si, bool allowImportedTransactions) { - const MyMoneySecurity& sec = MyMoneyFile::instance()->security(m_account.currencyId()); + Q_D(TransactionMatcher); + const MyMoneySecurity& sec = MyMoneyFile::instance()->security(d->m_account.currencyId()); // Now match the transactions. // // 'Matching' the transactions entails DELETING the end transaction, // and MODIFYING the start transaction as needed. // // There are a variety of ways that a transaction can conflict. // Post date, splits, amount are the ones that seem to matter. // TODO: Handle these conflicts intelligently, at least warning // the user, or better yet letting the user choose which to use. // // For now, we will just use the transaction details from the start // transaction. The only thing we'll take from the end transaction // are the bank ID's. // // What we have to do here is iterate over the splits in the end // transaction, and find the corresponding split in the start // transaction. If there is a bankID in the end split but not the // start split, add it to the start split. If there is a bankID // in BOTH, then this transaction cannot be merged (both transactions // were imported!!) If the corresponding start split cannot be // found and the end split has a bankID, we should probably just fail. // Although we could ADD it to the transaction. // ipwizard: Don't know if iterating over the transactions is a good idea. // In case of a split transaction recorded with KMyMoney and the transaction // data being imported consisting only of a single category assignment, this // does not make much sense. The same applies for investment transactions // stored in KMyMoney against imported transactions. I think a better solution // is to just base the match on the splits referencing the same (currently // selected) account. // verify, that tm is a manual (non-matched) transaction // allow matching two manual transactions if ((!allowImportedTransactions && tm.isImported()) || sm.isMatched()) throw MYMONEYEXCEPTION(i18n("First transaction does not match requirement for matching")); // verify that the amounts are the same, otherwise we should not be matching! if (sm.shares() != si.shares()) { - throw MYMONEYEXCEPTION(i18n("Splits for %1 have conflicting values (%2,%3)", m_account.name(), MyMoneyUtils::formatMoney(sm.shares(), m_account, sec), MyMoneyUtils::formatMoney(si.shares(), m_account, sec))); + throw MYMONEYEXCEPTION(i18n("Splits for %1 have conflicting values (%2,%3)", d->m_account.name(), MyMoneyUtils::formatMoney(sm.shares(), d->m_account, sec), MyMoneyUtils::formatMoney(si.shares(), d->m_account, sec))); } // ipwizard: I took over the code to keep the bank id found in the endMatchTransaction // This might not work for QIF imports as they don't setup this information. It sure // makes sense for OFX and HBCI. const QString& bankID = si.bankID(); if (!bankID.isEmpty()) { try { if (sm.bankID().isEmpty()) { sm.setBankID(bankID); tm.modifySplit(sm); } } catch (const MyMoneyException &e) { QString estr = e.what(); throw MYMONEYEXCEPTION(i18n("Unable to match all splits (%1)", estr)); } } // // we now allow matching of two non-imported transactions // // mark the split as cleared if it does not have a reconciliation information yet if (sm.reconcileFlag() == eMyMoney::Split::State::NotReconciled) { sm.setReconcileFlag(eMyMoney::Split::State::Cleared); } // if we don't have a payee assigned to the manually entered transaction // we use the one we found in the imported transaction if (sm.payeeId().isEmpty() && !si.payeeId().isEmpty()) { sm.setValue("kmm-orig-payee", sm.payeeId()); sm.setPayeeId(si.payeeId()); } // We use the imported postdate and keep the previous one for unmatch if (tm.postDate() != ti.postDate()) { sm.setValue("kmm-orig-postdate", tm.postDate().toString(Qt::ISODate)); tm.setPostDate(ti.postDate()); } // combine the two memos into one QString memo = sm.memo(); if (!si.memo().isEmpty() && si.memo() != memo) { sm.setValue("kmm-orig-memo", memo); if (!memo.isEmpty()) memo += '\n'; memo += si.memo(); } sm.setMemo(memo); // remember the split we matched sm.setValue("kmm-match-split", si.id()); sm.addMatch(ti); tm.modifySplit(sm); ti.modifySplit(si);/// MyMoneyFile::instance()->modifyTransaction(tm); // Delete the end transaction if it was stored in the engine if (!ti.id().isEmpty()) MyMoneyFile::instance()->removeTransaction(ti); } void TransactionMatcher::unmatch(const MyMoneyTransaction& _t, const MyMoneySplit& _s) { if (_s.isMatched()) { MyMoneyTransaction tm(_t); MyMoneySplit sm(_s); MyMoneyTransaction ti(sm.matchedTransaction()); MyMoneySplit si; // if we don't have a split, then we don't have a memo try { si = ti.splitById(sm.value("kmm-match-split")); } catch (const MyMoneyException &) { } sm.removeMatch(); // restore the postdate if modified if (!sm.value("kmm-orig-postdate").isEmpty()) { tm.setPostDate(QDate::fromString(sm.value("kmm-orig-postdate"), Qt::ISODate)); } // restore payee if modified if (!sm.value("kmm-orig-payee").isEmpty()) { sm.setPayeeId(sm.value("kmm-orig-payee")); } // restore memo if modified if (!sm.value("kmm-orig-memo").isEmpty()) { sm.setMemo(sm.value("kmm-orig-memo")); } sm.deletePair("kmm-orig-postdate"); sm.deletePair("kmm-orig-payee"); sm.deletePair("kmm-orig-memo"); sm.deletePair("kmm-match-split"); tm.modifySplit(sm); MyMoneyFile::instance()->modifyTransaction(tm); MyMoneyFile::instance()->addTransaction(ti); } } void TransactionMatcher::accept(const MyMoneyTransaction& _t, const MyMoneySplit& _s) { if (_s.isMatched()) { MyMoneyTransaction tm(_t); MyMoneySplit sm(_s); sm.removeMatch(); sm.deletePair("kmm-orig-postdate"); sm.deletePair("kmm-orig-payee"); sm.deletePair("kmm-orig-memo"); sm.deletePair("kmm-match-split"); tm.modifySplit(sm); MyMoneyFile::instance()->modifyTransaction(tm); } } diff --git a/kmymoney/dialogs/transactionmatcher.h b/kmymoney/dialogs/transactionmatcher.h index 640e7dbb8..07dae751e 100644 --- a/kmymoney/dialogs/transactionmatcher.h +++ b/kmymoney/dialogs/transactionmatcher.h @@ -1,101 +1,108 @@ /*************************************************************************** transactionmatcher.h ---------- begin : Tue Jul 08 2008 copyright : (C) 2008 by Thomas Baumgart email : Thomas Baumgart + (C) 2017 by Ł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. * * * ***************************************************************************/ #ifndef TRANSACTIONMATCHER_H #define TRANSACTIONMATCHER_H -#include "mymoneyaccount.h" +#include +class MyMoneySplit; class MyMoneyTransaction; +class MyMoneyAccount; +class TransactionMatcherPrivate; class TransactionMatcher { public: - TransactionMatcher(const MyMoneyAccount& acc); + Q_DISABLE_COPY(TransactionMatcher) + + explicit TransactionMatcher(const MyMoneyAccount& acc); + ~TransactionMatcher(); /** * This method matches the manual entered transaction @p tm with the imported * transaction @p ti based on the splits @p sm and @p si. If the match can be applied, * MyMoneyTransaction::addMatch() is used to include @p ti inside @p tm and the * engine data (MyMoneyFile) is updated. A possible bankid found in the imported * split is carried over into the manual transaction. * * The following things will be done in case of a match: * * - if the postdate differs between the two transactions * - the postdate of the manual entered transaction is stored in kmm-orig-postdate * - the postdate of the imported transaction is assigned to the resulting transaction * - if the payee differs between the two splits * - the payee of the manual split is stored in kmm-orig-payee * - the payee of the imported split is assigned to the resulting split * - if the reconciliation state is not-reconciled * - the reconciliation state is set to cleared * - the bankid of the imported transaction is assigned to the resulting transaction * - the resulting transaction will be updated and the imported transaction removed * from the engine * * The application of the match depends on the following items: * * - both share values of @p sm and @p si must be identical * - @p tm must be a non-imported (see below), non-matched transaction * - @p ti must be an imported transaction * * If @p allowImportedTransactions is true, @p tm may be an imported transaction. The * default of @p allowImportedTransactions is @p false. * * In case of errors, an exception is thrown. */ void match(MyMoneyTransaction tm, MyMoneySplit sm, MyMoneyTransaction ti, MyMoneySplit si, bool allowImportedTransactions = false); /** * This method is used to unmatch a previously matched transaction (see match() and findMatch() ) * and restore the original and imported transaction in the engine. * * The following things will be done in case @p t is a matched transaction: * * - the enclosed imported transaction is extracted and restored * - if the kvp contains a kmm-orig-payee record * - the payee is updated to this value if it still exists, otherwise the payee is left empty * - if the kvp contains a kmm-orig-postdate record * - the postdate of the transaction is changed to the value stored in this record * - a matching bankid is removed from the transaction * - the resulting transaction will be updated and the imported transaction inserted * into the engine * * In case of errors, an exception is thrown. */ void unmatch(const MyMoneyTransaction& t, const MyMoneySplit& s); /** * This method is used to accept a previously matched transaction (see match() and findMatch()) * * The following things will be done in case @p _t is a matched transaction * * - the enclosed imported transaction is removed * - the kvps kmm-orig-payee and kmm-orig-postdate are removed * - the resulting transaction will be updated * * In case of errors, an exception is thrown */ void accept(const MyMoneyTransaction& t, const MyMoneySplit& s); private: - MyMoneyAccount m_account; + TransactionMatcherPrivate * const d_ptr; + Q_DECLARE_PRIVATE(TransactionMatcher) }; - #endif diff --git a/kmymoney/kmymoney.cpp b/kmymoney/kmymoney.cpp index bee002e30..e497c5c4f 100644 --- a/kmymoney/kmymoney.cpp +++ b/kmymoney/kmymoney.cpp @@ -1,7583 +1,7592 @@ /*************************************************************************** kmymoney.cpp ------------------- copyright : (C) 2000 by Michael Edwardes (C) 2007 by Thomas Baumgart ****************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "config-kmymoney.h" #include "kmymoney.h" // ---------------------------------------------------------------------------- // Std C++ / STL Includes #include #include #include // ---------------------------------------------------------------------------- // QT Includes #include #include // only for performance tests #include #include #include #include #include #include #include #include #include #include #include #include #include +#include +#include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KF5Holidays_FOUND #include #include #endif // ---------------------------------------------------------------------------- // Project Includes #include "kmymoneyglobalsettings.h" #include "kmymoneyadaptor.h" #include "dialogs/settings/ksettingskmymoney.h" #include "dialogs/kbackupdlg.h" #include "dialogs/kenterscheduledlg.h" #include "dialogs/kconfirmmanualenterdlg.h" #include "dialogs/kmymoneypricedlg.h" #include "dialogs/kcurrencyeditdlg.h" #include "dialogs/kequitypriceupdatedlg.h" #include "dialogs/kmymoneyfileinfodlg.h" #include "dialogs/kfindtransactiondlg.h" #include "dialogs/knewbankdlg.h" #include "wizards/newinvestmentwizard/knewinvestmentwizard.h" #include "dialogs/knewaccountdlg.h" #include "dialogs/editpersonaldatadlg.h" #include "dialogs/kselectdatabasedlg.h" #include "dialogs/kcurrencycalculator.h" #include "dialogs/keditscheduledlg.h" #include "wizards/newloanwizard/keditloanwizard.h" #include "dialogs/kpayeereassigndlg.h" #include "dialogs/ktagreassigndlg.h" #include "dialogs/kcategoryreassigndlg.h" #include "wizards/endingbalancedlg/kendingbalancedlg.h" #include "dialogs/kbalancechartdlg.h" #include "dialogs/kgeneratesqldlg.h" #include "dialogs/kloadtemplatedlg.h" #include "dialogs/kgpgkeyselectiondlg.h" #include "dialogs/ktemplateexportdlg.h" #include "dialogs/transactionmatcher.h" #include "wizards/newuserwizard/knewuserwizard.h" #include "wizards/newaccountwizard/knewaccountwizard.h" #include "dialogs/kbalancewarning.h" #include "widgets/onlinejobmessagesview.h" #include "widgets/kmymoneymvccombo.h" #include "views/kmymoneyview.h" #include "views/konlinejoboutbox.h" #include "models/onlinejobmessagesmodel.h" #include "mymoney/mymoneyobject.h" #include "mymoney/mymoneyfile.h" #include "mymoney/mymoneyinstitution.h" #include "mymoney/mymoneyaccount.h" #include "mymoney/mymoneyaccountloan.h" #include "mymoney/mymoneysecurity.h" #include "mymoney/mymoneypayee.h" #include "mymoney/mymoneytag.h" #include "mymoney/mymoneybudget.h" #include "mymoney/mymoneysplit.h" #include "mymoney/mymoneyutils.h" #include "mymoney/mymoneystatement.h" #include "mymoney/storage/mymoneystoragedump.h" #include "mymoney/storage/imymoneystorage.h" #include "mymoney/mymoneyforecast.h" #include "mymoney/onlinejobmessage.h" #include "converter/mymoneystatementreader.h" #include "converter/mymoneytemplate.h" #include "plugins/interfaces/kmmviewinterface.h" #include "plugins/interfaces/kmmstatementinterface.h" #include "plugins/interfaces/kmmimportinterface.h" #include "plugins/interfaceloader.h" #include "plugins/onlinepluginextended.h" #include "pluginloader.h" #include "tasks/credittransfer.h" #include "icons/icons.h" #include "misc/webconnect.h" #include "storage/imymoneyserialize.h" #include "storage/mymoneystoragesql.h" #include #include "transactioneditor.h" #include "konlinetransferform.h" #include #include #include "kmymoneyutils.h" #include "kcreditswindow.h" #include "ledgerdelegate.h" #include "storageenums.h" #include "mymoneyenums.h" +#include "dialogenums.h" #include "misc/platformtools.h" using namespace Icons; static constexpr char recoveryKeyId[] = "59B0F826D2B08440"; // define the default period to warn about an expiring recoverkey to 30 days // but allows to override this setting during build time #ifndef RECOVER_KEY_EXPIRATION_WARNING #define RECOVER_KEY_EXPIRATION_WARNING 30 #endif const QHash KMyMoneyApp::s_Actions { {Action::FileOpenDatabase, QStringLiteral("open_database")}, {Action::FileSaveAsDatabase, QStringLiteral("saveas_database")}, {Action::FileBackup, QStringLiteral("file_backup")}, {Action::FileImportGNC, QStringLiteral("file_import_gnc")}, {Action::FileImportStatement, QStringLiteral("file_import_statement")}, {Action::FileImportTemplate, QStringLiteral("file_import_template")}, {Action::FileExportTemplate, QStringLiteral("file_export_template")}, {Action::FilePersonalData, QStringLiteral("view_personal_data")}, #ifdef KMM_DEBUG {Action::FileDump, QStringLiteral("file_dump")}, #endif {Action::FileInformation, QStringLiteral("view_file_info")}, {Action::EditFindTransaction, QStringLiteral("edit_find_transaction")}, {Action::ViewTransactionDetail, QStringLiteral("view_show_transaction_detail")}, {Action::ViewHideReconciled, QStringLiteral("view_hide_reconciled_transactions")}, {Action::ViewHideCategories, QStringLiteral("view_hide_unused_categories")}, {Action::ViewShowAll, QStringLiteral("view_show_all_accounts")}, {Action::InstitutionNew, QStringLiteral("institution_new")}, {Action::InstitutionEdit, QStringLiteral("institution_edit")}, {Action::InstitutionDelete, QStringLiteral("institution_delete")}, {Action::AccountNew, QStringLiteral("account_new")}, {Action::AccountOpen, QStringLiteral("account_open")}, {Action::AccountStartReconciliation, QStringLiteral("account_reconcile")}, {Action::AccountFinishReconciliation, QStringLiteral("account_reconcile_finish")}, {Action::AccountPostponeReconciliation, QStringLiteral("account_reconcile_postpone")}, {Action::AccountEdit, QStringLiteral("account_edit")}, {Action::AccountDelete, QStringLiteral("account_delete")}, {Action::AccountClose, QStringLiteral("account_close")}, {Action::AccountReopen, QStringLiteral("account_reopen")}, {Action::AccountTransactionReport, QStringLiteral("account_transaction_report")}, {Action::AccountBalanceChart, QStringLiteral("account_chart")}, {Action::AccountOnlineMap, QStringLiteral("account_online_map")}, {Action::AccountOnlineUnmap, QStringLiteral("account_online_unmap")}, {Action::AccountUpdateMenu, QStringLiteral("account_online_update_menu")}, {Action::AccountUpdate, QStringLiteral("account_online_update")}, {Action::AccountUpdateAll, QStringLiteral("account_online_update_all")}, {Action::AccountCreditTransfer, QStringLiteral("account_online_new_credit_transfer")}, {Action::CategoryNew, QStringLiteral("category_new")}, {Action::CategoryEdit, QStringLiteral("category_edit")}, {Action::CategoryDelete, QStringLiteral("category_delete")}, {Action::ToolCurrencies, QStringLiteral("tools_currency_editor")}, {Action::ToolPrices, QStringLiteral("tools_price_editor")}, {Action::ToolUpdatePrices, QStringLiteral("tools_update_prices")}, {Action::ToolConsistency, QStringLiteral("tools_consistency_check")}, {Action::ToolPerformance, QStringLiteral("tools_performancetest")}, {Action::ToolSQL, QStringLiteral("tools_generate_sql")}, {Action::ToolCalculator, QStringLiteral("tools_kcalc")}, {Action::SettingsAllMessages, QStringLiteral("settings_enable_messages")}, {Action::HelpShow, QStringLiteral("help_show_tip")}, {Action::TransactionNew, QStringLiteral("transaction_new")}, {Action::TransactionEdit, QStringLiteral("transaction_edit")}, {Action::TransactionEnter, QStringLiteral("transaction_enter")}, {Action::TransactionEditSplits, QStringLiteral("transaction_editsplits")}, {Action::TransactionCancel, QStringLiteral("transaction_cancel")}, {Action::TransactionDelete, QStringLiteral("transaction_delete")}, {Action::TransactionDuplicate, QStringLiteral("transaction_duplicate")}, {Action::TransactionMatch, QStringLiteral("transaction_match")}, {Action::TransactionAccept, QStringLiteral("transaction_accept")}, {Action::TransactionToggleReconciled, QStringLiteral("transaction_mark_toggle")}, {Action::TransactionToggleCleared, QStringLiteral("transaction_mark_cleared")}, {Action::TransactionReconciled, QStringLiteral("transaction_mark_reconciled")}, {Action::TransactionNotReconciled, QStringLiteral("transaction_mark_notreconciled")}, {Action::TransactionSelectAll, QStringLiteral("transaction_select_all")}, {Action::TransactionGoToAccount, QStringLiteral("transaction_goto_account")}, {Action::TransactionGoToPayee, QStringLiteral("transaction_goto_payee")}, {Action::TransactionCreateSchedule, QStringLiteral("transaction_create_schedule")}, {Action::TransactionAssignNumber, QStringLiteral("transaction_assign_number")}, {Action::TransactionCombine, QStringLiteral("transaction_combine")}, {Action::TransactionCopySplits, QStringLiteral("transaction_copy_splits")}, {Action::TransactionMoveMenu, QStringLiteral("transaction_move_menu")}, {Action::TransactionMarkMenu, QStringLiteral("transaction_mark_menu")}, {Action::TransactionContextMarkMenu, QStringLiteral("transaction_context_mark_menu")}, {Action::InvestmentNew, QStringLiteral("investment_new")}, {Action::InvestmentEdit, QStringLiteral("investment_edit")}, {Action::InvestmentDelete, QStringLiteral("investment_delete")}, {Action::InvestmentOnlinePrice, QStringLiteral("investment_online_price_update")}, {Action::InvestmentManualPrice, QStringLiteral("investment_manual_price_update")}, {Action::ScheduleNew, QStringLiteral("schedule_new")}, {Action::ScheduleEdit, QStringLiteral("schedule_edit")}, {Action::ScheduleDelete, QStringLiteral("schedule_delete")}, {Action::ScheduleDuplicate, QStringLiteral("schedule_duplicate")}, {Action::ScheduleEnter, QStringLiteral("schedule_enter")}, {Action::ScheduleSkip, QStringLiteral("schedule_skip")}, {Action::PayeeNew, QStringLiteral("payee_new")}, {Action::PayeeRename, QStringLiteral("payee_rename")}, {Action::PayeeDelete, QStringLiteral("payee_delete")}, {Action::PayeeMerge, QStringLiteral("payee_merge")}, {Action::TagNew, QStringLiteral("tag_new")}, {Action::TagRename, QStringLiteral("tag_rename")}, {Action::TagDelete, QStringLiteral("tag_delete")}, {Action::BudgetNew, QStringLiteral("budget_new")}, {Action::BudgetRename, QStringLiteral("budget_rename")}, {Action::BudgetDelete, QStringLiteral("budget_delete")}, {Action::BudgetCopy, QStringLiteral("budget_copy")}, {Action::BudgetChangeYear, QStringLiteral("budget_change_year")}, {Action::BudgetForecast, QStringLiteral("budget_forecast")}, {Action::CurrencyNew, QStringLiteral("currency_new")}, {Action::CurrencyRename, QStringLiteral("currency_rename")}, {Action::CurrencyDelete, QStringLiteral("currency_delete")}, {Action::CurrencySetBase, QStringLiteral("currency_setbase")}, {Action::PriceNew, QStringLiteral("price_new")}, {Action::PriceEdit, QStringLiteral("price_edit")}, {Action::PriceUpdate, QStringLiteral("price_update")}, {Action::PriceDelete, QStringLiteral("price_delete")}, #ifdef KMM_DEBUG {Action::WizardNewUser, QStringLiteral("new_user_wizard")}, {Action::DebugTraces, QStringLiteral("debug_traces")}, #endif {Action::DebugTimers, QStringLiteral("debug_timers")}, {Action::OnlineJobDelete, QStringLiteral("onlinejob_delete")}, {Action::OnlineJobEdit, QStringLiteral("onlinejob_edit")}, {Action::OnlineJobLog, QStringLiteral("onlinejob_log")}, }; enum backupStateE { BACKUP_IDLE = 0, BACKUP_MOUNTING, BACKUP_COPYING, BACKUP_UNMOUNTING }; class KMyMoneyApp::Private { public: Private(KMyMoneyApp *app) : q(app), m_ft(0), m_moveToAccountSelector(0), m_statementXMLindex(0), m_balanceWarning(0), m_collectingStatements(false), m_pluginLoader(0), m_backupResult(0), m_backupMount(0), m_ignoreBackupExitCode(false), m_myMoneyView(0), m_progressBar(0), m_smtReader(0), m_searchDlg(0), m_autoSaveTimer(0), m_progressTimer(0), m_inAutoSaving(false), m_transactionEditor(0), m_endingBalanceDlg(0), m_saveEncrypted(0), m_additionalKeyLabel(0), m_additionalKeyButton(0), m_recentFiles(0), #ifdef KF5Holidays_FOUND m_holidayRegion(0), #endif m_applicationIsReady(true), m_webConnect(new WebConnect(app)) { // since the days of the week are from 1 to 7, // and a day of the week is used to index this bit array, // resize the array to 8 elements (element 0 is left unused) m_processingDays.resize(8); } void closeFile(); void unlinkStatementXML(); void moveInvestmentTransaction(const QString& fromId, const QString& toId, const MyMoneyTransaction& t); QList > automaticReconciliation(const MyMoneyAccount &account, const QList > &transactions, const MyMoneyMoney &amount); /** * The public interface. */ KMyMoneyApp * const q; MyMoneyFileTransaction* m_ft; kMyMoneyAccountSelector* m_moveToAccountSelector; int m_statementXMLindex; KBalanceWarning* m_balanceWarning; bool m_collectingStatements; QStringList m_statementResults; KMyMoneyPlugin::PluginLoader* m_pluginLoader; QString m_lastPayeeEnteredId; /** the configuration object of the application */ KSharedConfigPtr m_config; /** * @brief List of all plugged plugins * * The key is the file name of the plugin. */ QMap m_plugins; /** * @brief List of plugged importer plugins * * The key is the objectName of the plugin. */ QMap m_importerPlugins; /** * @brief List of plugged online plugins * * The key is the objectName of the plugin. */ QMap m_onlinePlugins; /** * The following variable represents the state while crafting a backup. * It can have the following values * * - IDLE: the default value if not performing a backup * - MOUNTING: when a mount command has been issued * - COPYING: when a copy command has been issued * - UNMOUNTING: when an unmount command has been issued */ backupStateE m_backupState; /** * This variable keeps the result of the backup operation. */ int m_backupResult; /** * This variable is set, when the user selected to mount/unmount * the backup volume. */ bool m_backupMount; /** * Flag for internal run control */ bool m_ignoreBackupExitCode; KProcess m_proc; /// A pointer to the view holding the tabs. KMyMoneyView *m_myMoneyView; /// The URL of the file currently being edited when open. QUrl m_fileName; bool m_startDialog; QString m_mountpoint; QProgressBar* m_progressBar; QTime m_lastUpdate; QLabel* m_statusLabel; MyMoneyStatementReader* m_smtReader; // allows multiple imports to be launched trough web connect and to be executed sequentially QQueue m_importUrlsQueue; KFindTransactionDlg* m_searchDlg; QObject* m_pluginInterface; MyMoneyAccount m_selectedAccount; MyMoneyAccount m_reconciliationAccount; MyMoneyAccount m_selectedInvestment; MyMoneyInstitution m_selectedInstitution; MyMoneySchedule m_selectedSchedule; MyMoneySecurity m_selectedCurrency; MyMoneyPrice m_selectedPrice; QList m_selectedPayees; QList m_selectedTags; QList m_selectedBudgets; KMyMoneyRegister::SelectedTransactions m_selectedTransactions; // This is Auto Saving related bool m_autoSaveEnabled; QTimer* m_autoSaveTimer; QTimer* m_progressTimer; int m_autoSavePeriod; bool m_inAutoSaving; // pointer to the current transaction editor TransactionEditor* m_transactionEditor; // Reconciliation dialog KEndingBalanceDlg* m_endingBalanceDlg; // Pointer to the combo box used for key selection during // File/Save as KComboBox* m_saveEncrypted; // id's that need to be remembered QString m_accountGoto, m_payeeGoto; QStringList m_additionalGpgKeys; QLabel* m_additionalKeyLabel; QPushButton* m_additionalKeyButton; KRecentFilesAction* m_recentFiles; #ifdef KF5Holidays_FOUND // used by the calendar interface for schedules KHolidays::HolidayRegion* m_holidayRegion; #endif QBitArray m_processingDays; QMap m_holidayMap; QStringList m_consistencyCheckResult; bool m_applicationIsReady; WebConnect* m_webConnect; // methods void consistencyCheck(bool alwaysDisplayResults); static void setThemedCSS(); void copyConsistencyCheckResults(); void saveConsistencyCheckResults(); }; KMyMoneyApp::KMyMoneyApp(QWidget* parent) : KXmlGuiWindow(parent), d(new Private(this)) { #ifdef KMM_DBUS new KmymoneyAdaptor(this); QDBusConnection::sessionBus().registerObject("/KMymoney", this); QDBusConnection::sessionBus().interface()->registerService( "org.kde.kmymoney", QDBusConnectionInterface::DontQueueService); #endif // Register the main engine types used as meta-objects qRegisterMetaType("MyMoneyMoney"); qRegisterMetaType("MyMoneySecurity"); // preset the pointer because we need it during the course of this constructor kmymoney = this; d->m_config = KSharedConfig::openConfig(); d->setThemedCSS(); MyMoneyTransactionFilter::setFiscalYearStart(KMyMoneyGlobalSettings::firstFiscalMonth(), KMyMoneyGlobalSettings::firstFiscalDay()); updateCaption(true); QFrame* frame = new QFrame; frame->setFrameStyle(QFrame::NoFrame); // values for margin (11) and spacing(6) taken from KDialog implementation QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom, frame); layout->setContentsMargins(2, 2, 2, 2); layout->setSpacing(6); { QString themeName = KMyMoneySettings::iconsTheme(); // get theme user wants if (!themeName.isEmpty() && themeName != QLatin1Literal("system")) // if it isn't default theme then set it QIcon::setThemeName(themeName); Icons::setIconThemeNames(QIcon::themeName()); // get whatever theme user ends up with and hope our icon names will fit that theme } initStatusBar(); initActions(); initDynamicMenus(); d->m_myMoneyView = new KMyMoneyView(this/*the global variable kmymoney is not yet assigned. So we pass it here*/); layout->addWidget(d->m_myMoneyView, 10); connect(d->m_myMoneyView, &KMyMoneyView::aboutToChangeView, this, &KMyMoneyApp::slotResetSelections); connect(d->m_myMoneyView, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), this, SLOT(slotUpdateActions())); connectActionsAndViews(); /////////////////////////////////////////////////////////////////// // call inits to invoke all other construction parts readOptions(); // now initialize the plugin structure createInterfaces(); loadPlugins(); setCentralWidget(frame); connect(&d->m_proc, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotBackupHandleEvents())); // force to show the home page if the file is closed connect(actionCollection()->action(s_Actions[Action::ViewTransactionDetail]), &QAction::toggled, d->m_myMoneyView, &KMyMoneyView::slotShowTransactionDetail); d->m_backupState = BACKUP_IDLE; QLocale locale; int weekStart = locale.firstDayOfWeek(); int weekEnd = weekStart-1; if (weekEnd < Qt::Monday) { weekEnd = Qt::Sunday; } bool startFirst = (weekStart < weekEnd); for (int i = 0; i < 8; i++) { if (startFirst) d->m_processingDays.setBit(i, (i >= weekStart && i <= weekEnd)); else d->m_processingDays.setBit(i, (i >= weekStart || i <= weekEnd)); } d->m_autoSaveTimer = new QTimer(this); d->m_progressTimer = new QTimer(this); connect(d->m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave())); connect(d->m_progressTimer, SIGNAL(timeout()), this, SLOT(slotStatusProgressDone())); // make sure, we get a note when the engine changes state connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotDataChanged())); // connect the WebConnect server connect(d->m_webConnect, SIGNAL(gotUrl(QUrl)), this, SLOT(webConnect(QUrl))); // make sure we have a balance warning object d->m_balanceWarning = new KBalanceWarning(this); // setup the initial configuration slotUpdateConfiguration(); // kickstart date change timer slotDateChanged(); connect(this, SIGNAL(fileLoaded(QUrl)), onlineJobAdministration::instance(), SLOT(updateOnlineTaskProperties())); } KMyMoneyApp::~KMyMoneyApp() { // delete cached objects since the are in the way // when unloading the plugins onlineJobAdministration::instance()->clearCaches(); // we need to unload all plugins before we destroy anything else unloadPlugins(); delete d->m_searchDlg; delete d->m_transactionEditor; delete d->m_endingBalanceDlg; delete d->m_moveToAccountSelector; #ifdef KF5Holidays_FOUND delete d->m_holidayRegion; #endif delete d; } QUrl KMyMoneyApp::lastOpenedURL() { QUrl url = d->m_startDialog ? QUrl() : d->m_fileName; if (!url.isValid()) { url = QUrl::fromUserInput(readLastUsedFile()); } ready(); return url; } void KMyMoneyApp::slotObjectDestroyed(QObject* o) { if (o == d->m_moveToAccountSelector) { d->m_moveToAccountSelector = 0; } } void KMyMoneyApp::slotInstallConsistencyCheckContextMenu() { // this code relies on the implementation of KMessageBox::informationList to add a context menu to that list, // please adjust it if it's necessary or rewrite the way the consistency check results are displayed if (QWidget* dialog = QApplication::activeModalWidget()) { if (QListWidget* widget = dialog->findChild()) { // give the user a hint that the data can be saved widget->setToolTip(i18n("This is the consistency check log, use the context menu to copy or save it.")); widget->setWhatsThis(widget->toolTip()); widget->setContextMenuPolicy(Qt::CustomContextMenu); connect(widget, SIGNAL(customContextMenuRequested(QPoint)), SLOT(slotShowContextMenuForConsistencyCheck(QPoint))); } } } void KMyMoneyApp::slotShowContextMenuForConsistencyCheck(const QPoint &pos) { // allow the user to save the consistency check results if (QWidget* widget = qobject_cast< QWidget* >(sender())) { QMenu contextMenu(widget); QAction* copy = new QAction(i18n("Copy to clipboard"), widget); QAction* save = new QAction(i18n("Save to file"), widget); contextMenu.addAction(copy); contextMenu.addAction(save); QAction *result = contextMenu.exec(widget->mapToGlobal(pos)); if (result == copy) { // copy the consistency check results to the clipboard d->copyConsistencyCheckResults(); } else if (result == save) { // save the consistency check results to a file d->saveConsistencyCheckResults(); } } } void KMyMoneyApp::createTransactionMoveMenu() { if (!d->m_moveToAccountSelector) { QWidget* w = factory()->container("transaction_move_menu", this); QMenu *menu = dynamic_cast(w); if (menu) { QWidgetAction *accountSelectorAction = new QWidgetAction(menu); d->m_moveToAccountSelector = new kMyMoneyAccountSelector(menu, 0, false); d->m_moveToAccountSelector->setObjectName("transaction_move_menu_selector"); accountSelectorAction->setDefaultWidget(d->m_moveToAccountSelector); menu->addAction(accountSelectorAction); connect(d->m_moveToAccountSelector, SIGNAL(destroyed(QObject*)), this, SLOT(slotObjectDestroyed(QObject*))); connect(d->m_moveToAccountSelector, SIGNAL(itemSelected(QString)), this, SLOT(slotMoveToAccount(QString))); } } } void KMyMoneyApp::initDynamicMenus() { connect(this, SIGNAL(accountSelected(MyMoneyAccount)), this, SLOT(slotUpdateMoveToAccountMenu())); connect(this, SIGNAL(transactionsSelected(KMyMoneyRegister::SelectedTransactions)), this, SLOT(slotUpdateMoveToAccountMenu())); connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotUpdateMoveToAccountMenu())); } void KMyMoneyApp::initActions() { KActionCollection *aC = actionCollection(); // ************* // Adding standard actions // ************* KStandardAction::openNew(this, &KMyMoneyApp::slotFileNew, aC); KStandardAction::open(this, &KMyMoneyApp::slotFileOpen, aC); d->m_recentFiles = KStandardAction::openRecent(this, &KMyMoneyApp::slotFileOpenRecent, aC); KStandardAction::save(this, &KMyMoneyApp::slotFileSave, aC); KStandardAction::saveAs(this, &KMyMoneyApp::slotFileSaveAs, aC); KStandardAction::close(this, &KMyMoneyApp::slotFileClose, aC); KStandardAction::quit(this, &KMyMoneyApp::slotFileQuit, aC); KStandardAction::print(this, &KMyMoneyApp::slotPrintView, aC); KStandardAction::preferences(this, &KMyMoneyApp::slotSettings, aC); /* Look-up table for all custom actions. It's required for: 1) building QList with QActions to be added to ActionCollection 2) adding custom features to QActions like e.g. overlaid icon or keyboard shortcut */ QHash lutActions; // ************* // Adding all actions // ************* { // struct for QAction's vital (except icon) informations struct actionInfo { Action action; KMyMoneyAppFunc callback; QString text; Icon icon; }; const QVector actionInfos { // ************* // The File menu // ************* {Action::FileOpenDatabase, &KMyMoneyApp::slotOpenDatabase, i18n("Open database..."), Icon::SVNUpdate}, {Action::FileSaveAsDatabase, &KMyMoneyApp::slotSaveAsDatabase, i18n("Save as database..."), Icon::FileArchiver}, {Action::FileBackup, &KMyMoneyApp::slotBackupFile, i18n("Backup..."), Icon::Empty}, {Action::FileImportGNC, &KMyMoneyApp::slotGncImport, i18n("GnuCash..."), Icon::Empty}, {Action::FileImportStatement, &KMyMoneyApp::slotStatementImport, i18n("Statement file..."), Icon::Empty}, {Action::FileImportTemplate, &KMyMoneyApp::slotLoadAccountTemplates, i18n("Account Template..."), Icon::Empty}, {Action::FileExportTemplate, &KMyMoneyApp::slotSaveAccountTemplates, i18n("Account Template..."), Icon::Empty}, {Action::FilePersonalData, &KMyMoneyApp::slotFileViewPersonal, i18n("Personal Data..."), Icon::UserProperties}, #ifdef KMM_DEBUG {Action::FileDump, &KMyMoneyApp::slotFileFileInfo, i18n("Dump Memory"), Icon::Empty}, #endif {Action::FileInformation, &KMyMoneyApp::slotFileInfoDialog, i18n("File-Information..."), Icon::DocumentProperties}, // ************* // The Edit menu // ************* {Action::EditFindTransaction, &KMyMoneyApp::slotFindTransaction, i18n("Find transaction..."), Icon::Empty}, // ************* // The View menu // ************* {Action::ViewTransactionDetail, &KMyMoneyApp::slotShowTransactionDetail, i18n("Show Transaction Detail"), Icon::ViewTransactionDetail}, {Action::ViewHideReconciled, &KMyMoneyApp::slotHideReconciledTransactions, i18n("Hide reconciled transactions"), Icon::HideReconciled}, {Action::ViewHideCategories, &KMyMoneyApp::slotHideUnusedCategories, i18n("Hide unused categories"), Icon::HideCategories}, {Action::ViewShowAll, &KMyMoneyApp::slotShowAllAccounts, i18n("Show all accounts"), Icon::Empty}, // ********************* // The institutions menu // ********************* {Action::InstitutionNew, &KMyMoneyApp::slotInstitutionNew, i18n("New institution..."), Icon::Empty}, {Action::InstitutionEdit, &KMyMoneyApp::slotInstitutionEditEmpty, i18n("Edit institution..."), Icon::Empty}, {Action::InstitutionDelete, &KMyMoneyApp::slotInstitutionDelete, i18n("Delete institution..."), Icon::Empty}, // ***************** // The accounts menu // ***************** {Action::AccountNew, &KMyMoneyApp::slotAccountNew, i18n("New account..."), Icon::Empty}, {Action::AccountOpen, &KMyMoneyApp::slotAccountOpenEmpty, i18n("Open ledger"), Icon::ViewFinancialList}, {Action::AccountStartReconciliation, &KMyMoneyApp::slotAccountReconcileStart, i18n("Reconcile..."), Icon::Reconcile}, {Action::AccountFinishReconciliation, &KMyMoneyApp::slotAccountReconcileFinish, i18nc("Finish reconciliation", "Finish"), Icon::Empty}, {Action::AccountPostponeReconciliation, &KMyMoneyApp::slotAccountReconcilePostpone, i18n("Postpone reconciliation"), Icon::MediaPlaybackPause}, {Action::AccountEdit, &KMyMoneyApp::slotAccountEdit, i18n("Edit account..."), Icon::Empty}, {Action::AccountDelete, &KMyMoneyApp::slotAccountDelete, i18n("Delete account..."), Icon::Empty}, {Action::AccountClose, &KMyMoneyApp::slotAccountClose, i18n("Close account"), Icon::Empty}, {Action::AccountReopen, &KMyMoneyApp::slotAccountReopen, i18n("Reopen account"), Icon::Empty}, {Action::AccountTransactionReport, &KMyMoneyApp::slotAccountTransactionReport, i18n("Transaction report"), Icon::ViewFinancialList}, {Action::AccountBalanceChart, &KMyMoneyApp::slotAccountChart, i18n("Show balance chart..."), Icon::OfficeChartLine}, {Action::AccountOnlineMap, &KMyMoneyApp::slotAccountMapOnline, i18n("Map account..."), Icon::NewsSubscribe}, {Action::AccountOnlineUnmap, &KMyMoneyApp::slotAccountUnmapOnline, i18n("Unmap account..."), Icon::NewsUnsubscribe}, {Action::AccountUpdateMenu, &KMyMoneyApp::slotAccountUpdateOnline, i18nc("Update online accounts menu", "Update"), Icon::Empty}, {Action::AccountUpdate, &KMyMoneyApp::slotAccountUpdateOnline, i18n("Update account..."), Icon::Empty}, {Action::AccountUpdateAll, &KMyMoneyApp::slotAccountUpdateOnlineAll, i18n("Update all accounts..."), Icon::Empty}, {Action::AccountCreditTransfer, &KMyMoneyApp::slotNewOnlineTransfer, i18n("New credit transfer"), Icon::Empty}, // ******************* // The categories menu // ******************* {Action::CategoryNew, &KMyMoneyApp::slotCategoryNew, i18n("New category..."), Icon::Empty}, {Action::CategoryEdit, &KMyMoneyApp::slotAccountEdit, i18n("Edit category..."), Icon::Empty}, {Action::CategoryDelete, &KMyMoneyApp::slotAccountDelete, i18n("Delete category..."), Icon::Empty}, // ************** // The tools menu // ************** {Action::ToolCurrencies, &KMyMoneyApp::slotCurrencyDialog, i18n("Currencies..."), Icon::ViewCurrencyList}, {Action::ToolPrices, &KMyMoneyApp::slotPriceDialog, i18n("Prices..."), Icon::Empty}, {Action::ToolUpdatePrices, &KMyMoneyApp::slotEquityPriceUpdate, i18n("Update Stock and Currency Prices..."), Icon::Empty}, {Action::ToolConsistency, &KMyMoneyApp::slotFileConsistencyCheck, i18n("Consistency Check"), Icon::Empty}, {Action::ToolPerformance, &KMyMoneyApp::slotPerformanceTest, i18n("Performance-Test"), Icon::Fork}, {Action::ToolSQL, &KMyMoneyApp::slotGenerateSql, i18n("Generate Database SQL"), Icon::Empty}, {Action::ToolCalculator, &KMyMoneyApp::slotToolsStartKCalc, i18n("Calculator..."), Icon::AccessoriesCalculator}, // ***************** // The settings menu // ***************** {Action::SettingsAllMessages, &KMyMoneyApp::slotEnableMessages, i18n("Enable all messages"), Icon::Empty}, // ************* // The help menu // ************* {Action::HelpShow, &KMyMoneyApp::slotShowTipOfTheDay, i18n("&Show tip of the day"), Icon::Tip}, // *************************** // Actions w/o main menu entry // *************************** {Action::TransactionNew, &KMyMoneyApp::slotTransactionsNew, i18nc("New transaction button", "New"), Icon::Empty}, {Action::TransactionEdit, &KMyMoneyApp::slotTransactionsEdit, i18nc("Edit transaction button", "Edit"), Icon::Empty}, {Action::TransactionEnter, &KMyMoneyApp::slotTransactionsEnter, i18nc("Enter transaction", "Enter"), Icon::DialogOK}, {Action::TransactionEditSplits, &KMyMoneyApp::slotTransactionsEditSplits, i18nc("Edit split button", "Edit splits"), Icon::Split}, {Action::TransactionCancel, &KMyMoneyApp::slotTransactionsCancel, i18nc("Cancel transaction edit", "Cancel"), Icon::DialogCancel}, {Action::TransactionDelete, &KMyMoneyApp::slotTransactionsDelete, i18nc("Delete transaction", "Delete"), Icon::EditDelete}, {Action::TransactionDuplicate, &KMyMoneyApp::slotTransactionDuplicate, i18nc("Duplicate transaction", "Duplicate"), Icon::EditCopy}, {Action::TransactionMatch, &KMyMoneyApp::slotTransactionMatch, i18nc("Button text for match transaction", "Match"),Icon::Empty}, {Action::TransactionAccept, &KMyMoneyApp::slotTransactionsAccept, i18nc("Accept 'imported' and 'matched' transaction", "Accept"), Icon::Empty}, {Action::TransactionToggleReconciled, &KMyMoneyApp::slotToggleReconciliationFlag, i18nc("Toggle reconciliation flag", "Toggle"), Icon::Empty}, {Action::TransactionToggleCleared, &KMyMoneyApp::slotMarkTransactionCleared, i18nc("Mark transaction cleared", "Cleared"), Icon::Empty}, {Action::TransactionReconciled, &KMyMoneyApp::slotMarkTransactionReconciled, i18nc("Mark transaction reconciled", "Reconciled"), Icon::Empty}, {Action::TransactionNotReconciled, &KMyMoneyApp::slotMarkTransactionNotReconciled, i18nc("Mark transaction not reconciled", "Not reconciled"), Icon::Empty}, {Action::TransactionSelectAll, &KMyMoneyApp::selectAllTransactions, i18nc("Select all transactions", "Select all"), Icon::Empty}, {Action::TransactionGoToAccount, &KMyMoneyApp::slotTransactionGotoAccount, i18n("Go to account"), Icon::GoJump}, {Action::TransactionGoToPayee, &KMyMoneyApp::slotTransactionGotoPayee, i18n("Go to payee"), Icon::GoJump}, {Action::TransactionCreateSchedule, &KMyMoneyApp::slotTransactionCreateSchedule, i18n("Create scheduled transaction..."), Icon::AppointmentNew}, {Action::TransactionAssignNumber, &KMyMoneyApp::slotTransactionAssignNumber, i18n("Assign next number"), Icon::Empty}, {Action::TransactionCombine, &KMyMoneyApp::slotTransactionCombine, i18nc("Combine transactions", "Combine"), Icon::Empty}, {Action::TransactionCopySplits, &KMyMoneyApp::slotTransactionCopySplits, i18n("Copy splits"), Icon::Empty}, //Investment {Action::InvestmentNew, &KMyMoneyApp::slotInvestmentNew, i18n("New investment..."), Icon::Empty}, {Action::InvestmentEdit, &KMyMoneyApp::slotInvestmentEdit, i18n("Edit investment..."), Icon::Empty}, {Action::InvestmentDelete, &KMyMoneyApp::slotInvestmentDelete, i18n("Delete investment..."), Icon::Empty}, {Action::InvestmentOnlinePrice, &KMyMoneyApp::slotOnlinePriceUpdate, i18n("Online price update..."), Icon::Empty}, {Action::InvestmentManualPrice, &KMyMoneyApp::slotManualPriceUpdate, i18n("Manual price update..."), Icon::Empty}, //Schedule {Action::ScheduleNew, &KMyMoneyApp::slotScheduleNew, i18n("New scheduled transaction"), Icon::AppointmentNew}, {Action::ScheduleEdit, &KMyMoneyApp::slotScheduleEdit, i18n("Edit scheduled transaction"), Icon::DocumentEdit}, {Action::ScheduleDelete, &KMyMoneyApp::slotScheduleDelete, i18n("Delete scheduled transaction"), Icon::EditDelete}, {Action::ScheduleDuplicate, &KMyMoneyApp::slotScheduleDuplicate, i18n("Duplicate scheduled transaction"), Icon::EditCopy}, {Action::ScheduleEnter, &KMyMoneyApp::slotScheduleEnter, i18n("Enter next transaction..."), Icon::KeyEnter}, {Action::ScheduleSkip, &KMyMoneyApp::slotScheduleSkip, i18n("Skip next transaction..."), Icon::MediaSeekForward}, //Payees {Action::PayeeNew, &KMyMoneyApp::slotPayeeNew, i18n("New payee"), Icon::ListAddUser}, {Action::PayeeRename, &KMyMoneyApp::payeeRename, i18n("Rename payee"), Icon::PayeeRename}, {Action::PayeeDelete, &KMyMoneyApp::slotPayeeDelete, i18n("Delete payee"), Icon::ListRemoveUser}, {Action::PayeeMerge, &KMyMoneyApp::slotPayeeMerge, i18n("Merge payees"), Icon::PayeeMerge}, //Tags {Action::TagNew, &KMyMoneyApp::slotTagNew, i18n("New tag"), Icon::ListAddTag}, {Action::TagRename, &KMyMoneyApp::slotTagRename, i18n("Rename tag"), Icon::TagRename}, {Action::TagDelete, &KMyMoneyApp::slotTagDelete, i18n("Delete tag"), Icon::ListRemoveTag}, //Budget {Action::BudgetNew, &KMyMoneyApp::slotBudgetNew, i18n("New budget"), Icon::Empty}, {Action::BudgetRename, &KMyMoneyApp::budgetRename, i18n("Rename budget"), Icon::Empty}, {Action::BudgetDelete, &KMyMoneyApp::slotBudgetDelete, i18n("Delete budget"), Icon::Empty}, {Action::BudgetCopy, &KMyMoneyApp::slotBudgetCopy, i18n("Copy budget"), Icon::Empty}, {Action::BudgetChangeYear, &KMyMoneyApp::slotBudgetChangeYear, i18n("Change budget year"), Icon::ViewCalendar}, {Action::BudgetForecast, &KMyMoneyApp::slotBudgetForecast, i18n("Budget based on forecast"), Icon::ViewForecast}, //Currency actions {Action::CurrencyNew, &KMyMoneyApp::slotCurrencyNew, i18n("New currency"), Icon::Empty}, {Action::CurrencyRename, &KMyMoneyApp::currencyRename, i18n("Rename currency"), Icon::EditRename}, {Action::CurrencyDelete, &KMyMoneyApp::slotCurrencyDelete, i18n("Delete currency"), Icon::EditDelete}, {Action::CurrencySetBase, &KMyMoneyApp::slotCurrencySetBase, i18n("Select as base currency"), Icon::KMyMoney}, //Price actions {Action::PriceNew, &KMyMoneyApp::priceNew, i18n("New price..."), Icon::DocumentNew}, {Action::PriceEdit, &KMyMoneyApp::priceEdit, i18n("Edit price..."), Icon::DocumentEdit}, {Action::PriceUpdate, &KMyMoneyApp::priceOnlineUpdate, i18n("Online Price Update..."), Icon::Empty}, {Action::PriceDelete, &KMyMoneyApp::priceDelete, i18n("Delete price..."), Icon::EditDelete}, //debug actions #ifdef KMM_DEBUG {Action::WizardNewUser, &KMyMoneyApp::slotNewFeature, i18n("Test new feature"), Icon::Empty}, {Action::DebugTraces, &KMyMoneyApp::slotToggleTraces, i18n("Debug Traces"), Icon::Empty}, #endif {Action::DebugTimers, &KMyMoneyApp::slotToggleTimers, i18n("Debug Timers"), Icon::Empty}, // onlineJob actions {Action::OnlineJobDelete, &KMyMoneyApp::slotRemoveJob, i18n("Remove credit transfer"), Icon::EditDelete}, {Action::OnlineJobEdit, &KMyMoneyApp::slotEditJob, i18n("Edit credit transfer"), Icon::DocumentEdit}, {Action::OnlineJobLog, &KMyMoneyApp::slotOnlineJobLog, i18n("Show log"), Icon::Empty}, }; foreach (const auto info, actionInfos) { QAction *a = new QAction(0); // KActionCollection::addAction by name sets object name anyways, // so, as better alternative, set it here right from the start a->setObjectName(s_Actions.value(info.action)); a->setText(info.text); if (info.icon != Icon::Empty) // no need to set empty icon a->setIcon(QIcon::fromTheme(g_Icons.value(info.icon))); connect(a, &QAction::triggered, this, info.callback); lutActions.insert(info.action, a); // store QAction's pointer for later processing } } // ************* // Setting some of added actions checkable // ************* { // Some of acitions schould be checkable, // so set them here const QVector checkableActions { Action::ViewTransactionDetail, Action::ViewHideReconciled, Action::ViewHideCategories, #ifdef KMM_DEBUG Action::DebugTraces, #endif Action::ViewShowAll }; foreach (const auto it, checkableActions) lutActions[it]->setCheckable(true); } // ************* // Setting custom icons for some of added actions // ************* { // struct for QAction's icon overlays struct iconOverlayInfo { Action action; Icon icon; Icon overlay; Qt::Corner corner; }; const QVector actionOverlaidIcons { {Action::EditFindTransaction, Icon::ViewFinancialTransfer, Icon::EditFind, Qt::BottomRightCorner}, {Action::InstitutionNew, Icon::ViewBank, Icon::ListAdd, Qt::BottomRightCorner}, {Action::InstitutionEdit, Icon::ViewBank, Icon::DocumentEdit, Qt::BottomRightCorner}, {Action::InstitutionDelete, Icon::ViewBank, Icon::EditDelete, Qt::BottomRightCorner}, {Action::AccountNew, Icon::ViewBankAccount, Icon::ListAdd, Qt::TopRightCorner}, {Action::AccountFinishReconciliation, Icon::Merge, Icon::DialogOK, Qt::BottomRightCorner}, {Action::AccountEdit, Icon::ViewBankAccount, Icon::DocumentEdit, Qt::BottomRightCorner}, {Action::AccountDelete, Icon::ViewBankAccount, Icon::EditDelete, Qt::BottomRightCorner}, {Action::AccountClose, Icon::ViewBankAccount, Icon::DialogClose, Qt::BottomRightCorner}, {Action::AccountReopen, Icon::ViewBankAccount, Icon::DialogOK, Qt::BottomRightCorner}, {Action::AccountUpdateMenu, Icon::ViewBankAccount, Icon::Download, Qt::BottomRightCorner}, {Action::AccountUpdate, Icon::ViewBankAccount, Icon::Download, Qt::BottomRightCorner}, {Action::AccountUpdateAll, Icon::ViewBankAccount, Icon::Download, Qt::BottomRightCorner}, {Action::AccountCreditTransfer, Icon::ViewBankAccount, Icon::MailMessageNew, Qt::BottomRightCorner}, {Action::CategoryNew, Icon::ViewFinancialCategories, Icon::ListAdd, Qt::TopRightCorner}, {Action::CategoryEdit, Icon::ViewFinancialCategories, Icon::DocumentEdit, Qt::BottomRightCorner}, {Action::CategoryDelete, Icon::ViewFinancialCategories, Icon::EditDelete, Qt::BottomRightCorner}, {Action::ToolUpdatePrices, Icon::ViewInvestment, Icon::Download, Qt::BottomRightCorner}, {Action::TransactionNew, Icon::ViewFinancialTransfer, Icon::ListAdd, Qt::TopRightCorner}, {Action::TransactionEdit, Icon::ViewFinancialTransfer, Icon::DocumentEdit, Qt::BottomRightCorner}, {Action::TransactionMatch, Icon::ViewFinancialTransfer, Icon::DocumentImport, Qt::BottomRightCorner}, {Action::TransactionAccept, Icon::ViewFinancialTransfer, Icon::DialogOKApply, Qt::BottomRightCorner}, {Action::InvestmentNew, Icon::ViewInvestment, Icon::ListAdd, Qt::TopRightCorner}, {Action::InvestmentEdit, Icon::ViewInvestment, Icon::DocumentEdit, Qt::BottomRightCorner}, {Action::InvestmentDelete, Icon::ViewInvestment, Icon::EditDelete, Qt::BottomRightCorner}, {Action::InvestmentOnlinePrice, Icon::ViewInvestment, Icon::Download, Qt::BottomRightCorner}, {Action::BudgetNew, Icon::ViewTimeScheduleCalculus, Icon::ListAdd, Qt::TopRightCorner}, {Action::BudgetRename, Icon::ViewTimeScheduleCalculus, Icon::DocumentEdit, Qt::BottomRightCorner}, {Action::BudgetDelete, Icon::ViewTimeScheduleCalculus, Icon::EditDelete, Qt::BottomRightCorner}, {Action::BudgetCopy, Icon::ViewTimeScheduleCalculus, Icon::EditCopy, Qt::BottomRightCorner}, {Action::PriceUpdate, Icon::ViewCurrencyList, Icon::Download, Qt::BottomRightCorner} }; for(const auto& it : actionOverlaidIcons) lutActions[it.action]->setIcon(KMyMoneyUtils::overlayIcon(g_Icons[it.icon], g_Icons[it.overlay], it.corner)); } // ************* // Setting keyboard shortcuts for some of added actions // ************* { const QVector> actionShortcuts { {qMakePair(Action::EditFindTransaction, Qt::CTRL + Qt::Key_F)}, {qMakePair(Action::ViewTransactionDetail, Qt::CTRL + Qt::Key_T)}, {qMakePair(Action::ViewHideReconciled, Qt::CTRL + Qt::Key_R)}, {qMakePair(Action::ViewHideCategories, Qt::CTRL + Qt::Key_U)}, {qMakePair(Action::ViewShowAll, Qt::CTRL + Qt::SHIFT + Qt::Key_A)}, {qMakePair(Action::AccountStartReconciliation, Qt::CTRL + Qt::SHIFT + Qt::Key_R)}, {qMakePair(Action::TransactionNew, Qt::CTRL + Qt::Key_Insert)}, {qMakePair(Action::TransactionToggleReconciled, Qt::CTRL + Qt::Key_Space)}, {qMakePair(Action::TransactionToggleCleared, Qt::CTRL + Qt::Key_Alt + Qt::Key_Space)}, {qMakePair(Action::TransactionReconciled, Qt::CTRL + Qt::Key_Shift + Qt::Key_Space)}, {qMakePair(Action::TransactionSelectAll, Qt::CTRL + Qt::Key_A)}, #ifdef KMM_DEBUG {qMakePair(Action::WizardNewUser, Qt::CTRL + Qt::Key_G)}, #endif {qMakePair(Action::TransactionAssignNumber, Qt::CTRL + Qt::Key_Shift + Qt::Key_N)} }; for(const auto& it : actionShortcuts) aC->setDefaultShortcut(lutActions[it.first], it.second); } // ************* // Misc settings // ************* connect(onlineJobAdministration::instance(), &onlineJobAdministration::canSendCreditTransferChanged, lutActions.value(Action::AccountCreditTransfer), &QAction::setEnabled); // Setup transaction detail switch lutActions[Action::ViewTransactionDetail]->setChecked(KMyMoneyGlobalSettings::showRegisterDetailed()); lutActions[Action::ViewHideReconciled]->setChecked(KMyMoneyGlobalSettings::hideReconciledTransactions()); lutActions[Action::ViewHideCategories]->setChecked(KMyMoneyGlobalSettings::hideUnusedCategory()); lutActions[Action::ViewShowAll]->setChecked(false); // ************* // Adding actions to ActionCollection // ************* actionCollection()->addActions(lutActions.values()); // ************************ // Currently unused actions // ************************ #if 0 new KToolBarPopupAction(i18n("View back"), "go-previous", 0, this, SLOT(slotShowPreviousView()), actionCollection(), "go_back"); new KToolBarPopupAction(i18n("View forward"), "go-next", 0, this, SLOT(slotShowNextView()), actionCollection(), "go_forward"); action("go_back")->setEnabled(false); action("go_forward")->setEnabled(false); #endif // use the absolute path to your kmymoneyui.rc file for testing purpose in createGUI(); setupGUI(); // reconnect about app entry to dialog with full credits information QAction *aboutApp = aC->action(QString::fromLatin1(KStandardAction::name(KStandardAction::AboutApp))); aboutApp->disconnect(); connect(aboutApp, &QAction::triggered, this, &KMyMoneyApp::slotShowCredits); QMenu *menuContainer; menuContainer = static_cast(factory()->container(QStringLiteral("import"), this)); menuContainer->setIcon(QIcon::fromTheme(g_Icons[Icon::DocumentImport])); menuContainer = static_cast(factory()->container(QStringLiteral("export"), this)); menuContainer->setIcon(QIcon::fromTheme(g_Icons[Icon::DocumentExport])); } void KMyMoneyApp::connectActionsAndViews() { KOnlineJobOutbox *const outbox = d->m_myMoneyView->getOnlineJobOutbox(); Q_CHECK_PTR(outbox); QAction *const onlineJob_delete = actionCollection()->action(s_Actions[Action::OnlineJobDelete]); Q_CHECK_PTR(onlineJob_delete); connect(onlineJob_delete, SIGNAL(triggered()), outbox, SLOT(slotRemoveJob())); QAction *const onlineJob_edit = actionCollection()->action(s_Actions[Action::OnlineJobEdit]); Q_CHECK_PTR(onlineJob_edit); connect(onlineJob_edit, SIGNAL(triggered()), outbox, SLOT(slotEditJob())); } #ifdef KMM_DEBUG void KMyMoneyApp::dumpActions() const { const QList list = actionCollection()->actions(); foreach (const auto it, list) std::cout << qPrintable(it->objectName()) << ": " << qPrintable(it->text()) << std::endl; } #endif bool KMyMoneyApp::isActionToggled(const Action _a) { return actionCollection()->action(s_Actions[_a])->isChecked(); } void KMyMoneyApp::initStatusBar() { /////////////////////////////////////////////////////////////////// // STATUSBAR d->m_statusLabel = new QLabel; statusBar()->addWidget(d->m_statusLabel); ready(); // Initialization of progress bar taken from KDevelop ;-) d->m_progressBar = new QProgressBar; statusBar()->addWidget(d->m_progressBar); d->m_progressBar->setFixedHeight(d->m_progressBar->sizeHint().height() - 8); // hide the progress bar for now slotStatusProgressBar(-1, -1); } void KMyMoneyApp::saveOptions() { KConfigGroup grp = d->m_config->group("General Options"); grp.writeEntry("Geometry", size()); grp.writeEntry("Show Statusbar", actionCollection()->action(KStandardAction::name(KStandardAction::ShowStatusbar))->isChecked()); KConfigGroup toolbarGrp = d->m_config->group("mainToolBar"); toolBar("mainToolBar")->saveSettings(toolbarGrp); d->m_recentFiles->saveEntries(d->m_config->group("Recent Files")); } void KMyMoneyApp::readOptions() { KConfigGroup grp = d->m_config->group("General Options"); actionCollection()->action(s_Actions[Action::ViewHideReconciled])->setChecked(KMyMoneyGlobalSettings::hideReconciledTransactions()); actionCollection()->action(s_Actions[Action::ViewHideCategories])->setChecked(KMyMoneyGlobalSettings::hideUnusedCategory()); d->m_recentFiles->loadEntries(d->m_config->group("Recent Files")); // Startdialog is written in the settings dialog d->m_startDialog = grp.readEntry("StartDialog", true); } void KMyMoneyApp::resizeEvent(QResizeEvent* ev) { KMainWindow::resizeEvent(ev); updateCaption(true); } int KMyMoneyApp::askSaveOnClose() { int ans; if (KMyMoneyGlobalSettings::autoSaveOnClose()) { ans = KMessageBox::Yes; } else { ans = KMessageBox::warningYesNoCancel(this, i18n("The file has been changed, save it?")); } return ans; } bool KMyMoneyApp::queryClose() { if (!isReady()) return false; if (d->m_myMoneyView->dirty()) { int ans = askSaveOnClose(); if (ans == KMessageBox::Cancel) return false; else if (ans == KMessageBox::Yes) { bool saved = slotFileSave(); saveOptions(); return saved; } } if (d->m_myMoneyView->isDatabase()) slotFileClose(); // close off the database saveOptions(); return true; } ///////////////////////////////////////////////////////////////////// // SLOT IMPLEMENTATION ///////////////////////////////////////////////////////////////////// void KMyMoneyApp::slotFileInfoDialog() { QPointer dlg = new KMyMoneyFileInfoDlg(0); dlg->exec(); delete dlg; } void KMyMoneyApp::slotPerformanceTest() { // dump performance report to stderr int measurement[2]; QTime timer; MyMoneyAccount acc; qDebug("--- Starting performance tests ---"); // AccountList MyMoneyFile::instance()->preloadCache(); measurement[0] = measurement[1] = 0; timer.start(); for (int i = 0; i < 1000; ++i) { QList list; MyMoneyFile::instance()->accountList(list); measurement[i != 0] = timer.elapsed(); } std::cerr << "accountList()" << std::endl; std::cerr << "First time: " << measurement[0] << " msec" << std::endl; std::cerr << "Total time: " << (measurement[0] + measurement[1]) << " msec" << std::endl; std::cerr << "Average : " << (measurement[0] + measurement[1]) / 1000 << " msec" << std::endl; // Balance of asset account(s) MyMoneyFile::instance()->preloadCache(); measurement[0] = measurement[1] = 0; acc = MyMoneyFile::instance()->asset(); for (int i = 0; i < 1000; ++i) { timer.start(); MyMoneyMoney result = MyMoneyFile::instance()->balance(acc.id()); measurement[i != 0] += timer.elapsed(); } std::cerr << "balance(Asset)" << std::endl; std::cerr << "First time: " << measurement[0] << " msec" << std::endl; std::cerr << "Average : " << (measurement[0] + measurement[1]) / 1000 << " msec" << std::endl; // total balance of asset account MyMoneyFile::instance()->preloadCache(); measurement[0] = measurement[1] = 0; acc = MyMoneyFile::instance()->asset(); for (int i = 0; i < 1000; ++i) { timer.start(); MyMoneyMoney result = MyMoneyFile::instance()->totalBalance(acc.id()); measurement[i != 0] += timer.elapsed(); } std::cerr << "totalBalance(Asset)" << std::endl; std::cerr << "First time: " << measurement[0] << " msec" << std::endl; std::cerr << "Average : " << (measurement[0] + measurement[1]) / 1000 << " msec" << std::endl; // Balance of expense account(s) MyMoneyFile::instance()->preloadCache(); measurement[0] = measurement[1] = 0; acc = MyMoneyFile::instance()->expense(); for (int i = 0; i < 1000; ++i) { timer.start(); MyMoneyMoney result = MyMoneyFile::instance()->balance(acc.id()); measurement[i != 0] += timer.elapsed(); } std::cerr << "balance(Expense)" << std::endl; std::cerr << "First time: " << measurement[0] << " msec" << std::endl; std::cerr << "Average : " << (measurement[0] + measurement[1]) / 1000 << " msec" << std::endl; // total balance of expense account MyMoneyFile::instance()->preloadCache(); measurement[0] = measurement[1] = 0; acc = MyMoneyFile::instance()->expense(); timer.start(); for (int i = 0; i < 1000; ++i) { MyMoneyMoney result = MyMoneyFile::instance()->totalBalance(acc.id()); measurement[i != 0] = timer.elapsed(); } std::cerr << "totalBalance(Expense)" << std::endl; std::cerr << "First time: " << measurement[0] << " msec" << std::endl; std::cerr << "Total time: " << (measurement[0] + measurement[1]) << " msec" << std::endl; std::cerr << "Average : " << (measurement[0] + measurement[1]) / 1000 << " msec" << std::endl; // transaction list MyMoneyFile::instance()->preloadCache(); measurement[0] = measurement[1] = 0; if (MyMoneyFile::instance()->asset().accountCount()) { MyMoneyTransactionFilter filter(MyMoneyFile::instance()->asset().accountList()[0]); filter.setDateFilter(QDate(), QDate::currentDate()); QList list; timer.start(); for (int i = 0; i < 100; ++i) { list = MyMoneyFile::instance()->transactionList(filter); measurement[i != 0] = timer.elapsed(); } std::cerr << "transactionList()" << std::endl; std::cerr << "First time: " << measurement[0] << " msec" << std::endl; std::cerr << "Total time: " << (measurement[0] + measurement[1]) << " msec" << std::endl; std::cerr << "Average : " << (measurement[0] + measurement[1]) / 100 << " msec" << std::endl; } // transaction list MyMoneyFile::instance()->preloadCache(); measurement[0] = measurement[1] = 0; if (MyMoneyFile::instance()->asset().accountCount()) { MyMoneyTransactionFilter filter(MyMoneyFile::instance()->asset().accountList()[0]); filter.setDateFilter(QDate(), QDate::currentDate()); QList list; timer.start(); for (int i = 0; i < 100; ++i) { MyMoneyFile::instance()->transactionList(list, filter); measurement[i != 0] = timer.elapsed(); } std::cerr << "transactionList(list)" << std::endl; std::cerr << "First time: " << measurement[0] << " msec" << std::endl; std::cerr << "Total time: " << (measurement[0] + measurement[1]) << " msec" << std::endl; std::cerr << "Average : " << (measurement[0] + measurement[1]) / 100 << " msec" << std::endl; } MyMoneyFile::instance()->preloadCache(); } void KMyMoneyApp::slotFileNew() { KMSTATUS(i18n("Creating new document...")); slotFileClose(); if (!d->m_myMoneyView->fileOpen()) { // next line required until we move all file handling out of KMyMoneyView d->m_myMoneyView->newFile(); d->m_fileName = QUrl(); updateCaption(); NewUserWizard::Wizard *wizard = new NewUserWizard::Wizard(); if (wizard->exec() == QDialog::Accepted) { MyMoneyFileTransaction ft; MyMoneyFile* file = MyMoneyFile::instance(); try { // store the user info file->setUser(wizard->user()); // create and setup base currency file->addCurrency(wizard->baseCurrency()); file->setBaseCurrency(wizard->baseCurrency()); // create a possible institution MyMoneyInstitution inst = wizard->institution(); if (inst.name().length()) { file->addInstitution(inst); } // create a possible checking account MyMoneyAccount acc = wizard->account(); if (acc.name().length()) { acc.setInstitutionId(inst.id()); MyMoneyAccount asset = file->asset(); file->addAccount(acc, asset); // create possible opening balance transaction if (!wizard->openingBalance().isZero()) { file->createOpeningBalanceTransaction(acc, wizard->openingBalance()); } } // import the account templates QList templates = wizard->templates(); QList::iterator it_t; for (it_t = templates.begin(); it_t != templates.end(); ++it_t) { (*it_t).importTemplate(&progressCallback); } d->m_fileName = wizard->url(); ft.commit(); KMyMoneyGlobalSettings::setFirstTimeRun(false); // FIXME This is a bit clumsy. We re-read the freshly // created file to be able to run through all the // fixup logic and then save it to keep the modified // flag off. slotFileSave(); d->m_myMoneyView->readFile(d->m_fileName); slotFileSave(); // now keep the filename in the recent files used list //KRecentFilesAction *p = dynamic_cast(action(KStandardAction::name(KStandardAction::OpenRecent))); //if(p) d->m_recentFiles->addUrl(d->m_fileName); writeLastUsedFile(d->m_fileName.url()); } catch (const MyMoneyException &) { // next line required until we move all file handling out of KMyMoneyView d->m_myMoneyView->closeFile(); } if (wizard->startSettingsAfterFinished()) slotSettings(); } else { // next line required until we move all file handling out of KMyMoneyView d->m_myMoneyView->closeFile(); } delete wizard; updateCaption(); emit fileLoaded(d->m_fileName); } } QUrl KMyMoneyApp::selectFile(const QString& title, const QString& _path, const QString& mask, QFileDialog::FileMode mode, QWidget* widget) { QString path(_path); // if the path is not specified open the file dialog in the last used directory // 'kmymoney' is the keyword that identifies the last used directory in KFileDialog if (path.isEmpty()) { path = KRecentDirs::dir(":kmymoney-import"); } QPointer dialog = new QFileDialog(this, title, path, mask); dialog->setFileMode(mode); QUrl url; if (dialog->exec() == QDialog::Accepted && dialog != 0) { QList selectedUrls = dialog->selectedUrls(); if (!selectedUrls.isEmpty()) { url = selectedUrls.first(); if (_path.isEmpty()) { KRecentDirs::add(":kmymoney-import", url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path()); } } } // in case we have an additional widget, we remove it from the // dialog, so that the caller can still access it. Therefore, it is // the callers responsibility to delete the object if (widget) widget->setParent(0); delete dialog; return url; } // General open void KMyMoneyApp::slotFileOpen() { KMSTATUS(i18n("Open a file.")); QString prevDir = readLastUsedDir(); QPointer dialog = new QFileDialog(this, QString(), prevDir, i18n("KMyMoney files (*.kmy *.xml);;All files")); dialog->setFileMode(QFileDialog::ExistingFile); dialog->setAcceptMode(QFileDialog::AcceptOpen); if (dialog->exec() == QDialog::Accepted && dialog != nullptr) { slotFileOpenRecent(dialog->selectedUrls().first()); } delete dialog; } void KMyMoneyApp::slotOpenDatabase() { KMSTATUS(i18n("Open a file.")); QPointer dialog = new KSelectDatabaseDlg(QIODevice::ReadWrite); if (!dialog->checkDrivers()) { delete dialog; return; } if (dialog->exec() == QDialog::Accepted && dialog != 0) { slotFileOpenRecent(dialog->selectedURL()); } delete dialog; } bool KMyMoneyApp::isImportableFile(const QUrl &url) { bool result = false; // Iterate through the plugins and see if there's a loaded plugin who can handle it QMap::const_iterator it_plugin = d->m_importerPlugins.constBegin(); while (it_plugin != d->m_importerPlugins.constEnd()) { if ((*it_plugin)->isMyFormat(url.path())) { result = true; break; } ++it_plugin; } // If we did not find a match, try importing it as a KMM statement file, // which is really just for testing. the statement file is not exposed // to users. if (it_plugin == d->m_importerPlugins.constEnd()) if (MyMoneyStatement::isStatementFile(url.path())) result = true; // Place code here to test for QIF and other locally-supported formats // (i.e. not a plugin). If you add them here, be sure to add it to // the webConnect function. return result; } void KMyMoneyApp::slotFileOpenRecent(const QUrl &url) { KMSTATUS(i18n("Loading file...")); QUrl lastFile = d->m_fileName; // check if there are other instances which might have this file open QList list = instanceList(); QList::ConstIterator it; bool duplicate = false; #ifdef KMM_DBUS for (it = list.constBegin(); duplicate == false && it != list.constEnd(); ++it) { QDBusInterface remoteApp(*it, "/KMymoney", "org.kde.kmymoney"); QDBusReply reply = remoteApp.call("filename"); if (!reply.isValid()) { qDebug("D-Bus error while calling app->filename()"); } else { if (reply.value() == url.url()) { duplicate = true; } } } #endif if (!duplicate) { QUrl newurl = url; if ((newurl.scheme() == QLatin1String("sql"))) { const QString key = QLatin1String("driver"); // take care and convert some old url to their new counterpart QUrlQuery query(newurl); if (query.queryItemValue(key) == QLatin1String("QMYSQL3")) { // fix any old urls query.removeQueryItem(key); query.addQueryItem(key, QLatin1String("QMYSQL")); } if (query.queryItemValue(key) == QLatin1String("QSQLITE3")) { query.removeQueryItem(key); query.addQueryItem(key, QLatin1String("QSQLITE")); } newurl.setQuery(query); if (query.queryItemValue(key) == QLatin1String("QSQLITE")) { newurl.setUserInfo(QString()); newurl.setHost(QString()); } // check if a password is needed. it may be if the URL came from the last/recent file list QPointer dialog = new KSelectDatabaseDlg(QIODevice::ReadWrite, newurl); if (!dialog->checkDrivers()) { delete dialog; return; } // if we need to supply a password, then show the dialog // otherwise it isn't needed if ((query.queryItemValue("secure").toLower() == QLatin1String("yes")) && newurl.password().isEmpty()) { if (dialog->exec() == QDialog::Accepted && dialog != nullptr) { newurl = dialog->selectedURL(); } else { delete dialog; return; } } delete dialog; } // TODO: port KF5 (NetAccess) if ((newurl.scheme() == QLatin1String("sql")) || (newurl.isValid() /*&& KIO::NetAccess::exists(newurl, KIO::NetAccess::SourceSide, this)*/)) { slotFileClose(); if (!d->m_myMoneyView->fileOpen()) { try { if (d->m_myMoneyView->readFile(newurl)) { if ((d->m_myMoneyView->isNativeFile())) { d->m_fileName = newurl; updateCaption(); d->m_recentFiles->addUrl(newurl); writeLastUsedFile(newurl.toDisplayString(QUrl::PreferLocalFile)); } else { d->m_fileName = QUrl(); // imported files have no filename } // Check the schedules slotCheckSchedules(); } } catch (const MyMoneyException &e) { KMessageBox::sorry(this, i18n("Cannot open file as requested. Error was: %1", e.what())); } updateCaption(); emit fileLoaded(d->m_fileName); } else { /*fileOpen failed - should we do something or maybe fileOpen puts out the message... - it does for database*/ } } else { // newurl invalid slotFileClose(); KMessageBox::sorry(this, i18n("

%1 is either an invalid filename or the file does not exist. You can open another file or create a new one.

", url.toDisplayString(QUrl::PreferLocalFile)), i18n("File not found")); } } else { // isDuplicate KMessageBox::sorry(this, i18n("

File %1 is already opened in another instance of KMyMoney

", url.toDisplayString(QUrl::PreferLocalFile)), i18n("Duplicate open")); } } bool KMyMoneyApp::slotFileSave() { // if there's nothing changed, there's no need to save anything if (!d->m_myMoneyView->dirty()) return true; bool rc = false; KMSTATUS(i18n("Saving file...")); if (d->m_fileName.isEmpty()) return slotFileSaveAs(); d->consistencyCheck(false); /*if (myMoneyView->isDatabase()) { rc = myMoneyView->saveDatabase(m_fileName); // the 'save' function is no longer relevant for a database*/ setEnabled(false); rc = d->m_myMoneyView->saveFile(d->m_fileName, MyMoneyFile::instance()->value("kmm-encryption-key")); setEnabled(true); d->m_autoSaveTimer->stop(); updateCaption(); return rc; } void KMyMoneyApp::slotFileSaveAsFilterChanged(const QString& filter) { if (!d->m_saveEncrypted) return; if (filter.compare(QLatin1String("*.kmy"), Qt::CaseInsensitive) != 0) { d->m_saveEncrypted->setCurrentItem(0); d->m_saveEncrypted->setEnabled(false); } else { d->m_saveEncrypted->setEnabled(true); } } void KMyMoneyApp::slotManageGpgKeys() { QPointer dlg = new KGpgKeySelectionDlg(this); dlg->setKeys(d->m_additionalGpgKeys); if (dlg->exec() == QDialog::Accepted && dlg != 0) { d->m_additionalGpgKeys = dlg->keys(); d->m_additionalKeyLabel->setText(i18n("Additional encryption keys to be used: %1", d->m_additionalGpgKeys.count())); } delete dlg; } void KMyMoneyApp::slotKeySelected(int idx) { int cnt = 0; if (idx != 0) { cnt = d->m_additionalGpgKeys.count(); } d->m_additionalKeyLabel->setEnabled(idx != 0); d->m_additionalKeyButton->setEnabled(idx != 0); d->m_additionalKeyLabel->setText(i18n("Additional encryption keys to be used: %1", cnt)); } bool KMyMoneyApp::slotFileSaveAs() { bool rc = false; // in event of it being a database, ensure that all data is read into storage for saveas if (d->m_myMoneyView->isDatabase()) dynamic_cast(MyMoneyFile::instance()->storage())->fillStorage(); KMSTATUS(i18n("Saving file with a new filename...")); // fill the additional key list with the default d->m_additionalGpgKeys = KMyMoneyGlobalSettings::gpgRecipientList(); QWidget* vbox = new QWidget(); QVBoxLayout *vboxVBoxLayout = new QVBoxLayout(vbox); vboxVBoxLayout->setMargin(0); if (KGPGFile::GPGAvailable()) { QWidget* keyBox = new QWidget(vbox); QHBoxLayout *keyBoxHBoxLayout = new QHBoxLayout(keyBox); keyBoxHBoxLayout->setMargin(0); vboxVBoxLayout->addWidget(keyBox); QLabel *keyLabel = new QLabel(i18n("Encryption key to be used"), keyBox); keyBoxHBoxLayout->addWidget(keyLabel); d->m_saveEncrypted = new KComboBox(keyBox); keyBoxHBoxLayout->addWidget(d->m_saveEncrypted); QWidget* labelBox = new QWidget(vbox); QHBoxLayout *labelBoxHBoxLayout = new QHBoxLayout(labelBox); labelBoxHBoxLayout->setMargin(0); vboxVBoxLayout->addWidget(labelBox); d->m_additionalKeyLabel = new QLabel(i18n("Additional encryption keys to be used: %1", d->m_additionalGpgKeys.count()), labelBox); labelBoxHBoxLayout->addWidget(d->m_additionalKeyLabel); d->m_additionalKeyButton = new QPushButton(i18n("Manage additional keys"), labelBox); labelBoxHBoxLayout->addWidget(d->m_additionalKeyButton); connect(d->m_additionalKeyButton, SIGNAL(clicked()), this, SLOT(slotManageGpgKeys())); connect(d->m_saveEncrypted, SIGNAL(activated(int)), this, SLOT(slotKeySelected(int))); // fill the secret key list and combo box QStringList keyList; KGPGFile::secretKeyList(keyList); d->m_saveEncrypted->addItem(i18n("No encryption")); for (QStringList::iterator it = keyList.begin(); it != keyList.end(); ++it) { QStringList fields = (*it).split(':', QString::SkipEmptyParts); if (fields[0] != recoveryKeyId) { // replace parenthesis in name field with brackets QString name = fields[1]; name.replace('(', "["); name.replace(')', "]"); name = QString("%1 (0x%2)").arg(name).arg(fields[0]); d->m_saveEncrypted->addItem(name); if (name.contains(KMyMoneyGlobalSettings::gpgRecipient())) { d->m_saveEncrypted->setCurrentItem(name); } } } } QString prevDir; // don't prompt file name if not a native file if (d->m_myMoneyView->isNativeFile()) prevDir = readLastUsedDir(); QPointer dlg = new QFileDialog(this, i18n("Save As"), prevDir, QString(QLatin1String("%2 (%1);;")).arg(QStringLiteral("*.kmy")).arg(i18nc("KMyMoney (Filefilter)", "KMyMoney files")) + QString(QLatin1String("%2 (%1);;")).arg(QStringLiteral("*.xml")).arg(i18nc("XML (Filefilter)", "XML files")) + QString(QLatin1String("%2 (%1);;")).arg(QStringLiteral("*.anon.xml")).arg(i18nc("Anonymous (Filefilter)", "Anonymous files")) + QString(QLatin1String("%2 (%1);;")).arg(QStringLiteral("*")).arg(i18nc("All files (Filefilter)", "All files"))); dlg->setAcceptMode(QFileDialog::AcceptSave); connect(dlg, SIGNAL(filterChanged(QString)), this, SLOT(slotFileSaveAsFilterChanged(QString))); if (dlg->exec() == QDialog::Accepted && dlg != 0) { QUrl newURL = dlg->selectedUrls().first(); if (!newURL.fileName().isEmpty()) { d->consistencyCheck(false); // deleting the dialog will delete the combobox pointed to by d->m_saveEncrypted so get the key name here QString selectedKeyName; if (d->m_saveEncrypted && d->m_saveEncrypted->currentIndex() != 0) selectedKeyName = d->m_saveEncrypted->currentText(); d->m_saveEncrypted = 0; QString newName = newURL.toDisplayString(QUrl::PreferLocalFile); // append extension if not present if (!newName.endsWith(QLatin1String(".kmy"), Qt::CaseInsensitive) && !newName.endsWith(QLatin1String(".xml"), Qt::CaseInsensitive)) newName.append(QLatin1String(".kmy")); newURL = QUrl::fromUserInput(newName); d->m_recentFiles->addUrl(newURL); setEnabled(false); // If this is the anonymous file export, just save it, don't actually take the // name, or remember it! Don't even try to encrypt it if (newName.endsWith(QLatin1String(".anon.xml"), Qt::CaseInsensitive)) rc = d->m_myMoneyView->saveFile(newURL); else { d->m_fileName = newURL; QString encryptionKeys; QRegExp keyExp(".* \\((.*)\\)"); if (keyExp.indexIn(selectedKeyName) != -1) { encryptionKeys = keyExp.cap(1); } if (!d->m_additionalGpgKeys.isEmpty()) { if (!encryptionKeys.isEmpty()) encryptionKeys.append(QLatin1Char(',')); encryptionKeys.append(d->m_additionalGpgKeys.join(QLatin1Char(','))); } rc = d->m_myMoneyView->saveFile(d->m_fileName, encryptionKeys); //write the directory used for this file as the default one for next time. writeLastUsedDir(newURL.toDisplayString(QUrl::RemoveFilename | QUrl::PreferLocalFile | QUrl::StripTrailingSlash)); writeLastUsedFile(newName); } d->m_autoSaveTimer->stop(); setEnabled(true); } } delete dlg; updateCaption(); return rc; } void KMyMoneyApp::slotSaveAsDatabase() { saveAsDatabase(); } bool KMyMoneyApp::saveAsDatabase() { bool rc = false; QUrl oldUrl; // in event of it being a database, ensure that all data is read into storage for saveas if (d->m_myMoneyView->isDatabase()) { dynamic_cast(MyMoneyFile::instance()->storage())->fillStorage(); oldUrl = d->m_fileName.isEmpty() ? lastOpenedURL() : d->m_fileName; } KMSTATUS(i18n("Saving file to database...")); QPointer dialog = new KSelectDatabaseDlg(QIODevice::WriteOnly); QUrl url = oldUrl; if (!dialog->checkDrivers()) { delete dialog; return (false); } while (oldUrl == url && dialog->exec() == QDialog::Accepted && dialog != 0) { url = dialog->selectedURL(); // If the protocol is SQL for the old and new, and the hostname and database names match // Let the user know that the current database cannot be saved on top of itself. if (url.scheme() == "sql" && oldUrl.scheme() == "sql" && oldUrl.host() == url.host() && QUrlQuery(oldUrl).queryItemValue("driver") == QUrlQuery(url).queryItemValue("driver") && oldUrl.path().right(oldUrl.path().length() - 1) == url.path().right(url.path().length() - 1)) { KMessageBox::sorry(this, i18n("Cannot save to current database.")); } else { try { rc = d->m_myMoneyView->saveAsDatabase(url); } catch (const MyMoneyException &e) { KMessageBox::sorry(this, i18n("Cannot save to current database: %1", e.what())); } } } delete dialog; if (rc) { //KRecentFilesAction *p = dynamic_cast(action("file_open_recent")); //if(p) d->m_recentFiles->addUrl(url); writeLastUsedFile(url.toDisplayString(QUrl::PreferLocalFile)); } d->m_autoSaveTimer->stop(); updateCaption(); return rc; } void KMyMoneyApp::slotFileCloseWindow() { KMSTATUS(i18n("Closing window...")); if (d->m_myMoneyView->dirty()) { int answer = askSaveOnClose(); if (answer == KMessageBox::Cancel) return; else if (answer == KMessageBox::Yes) slotFileSave(); } close(); } void KMyMoneyApp::slotFileClose() { bool okToSelect = true; // check if transaction editor is open and ask user what he wants to do slotTransactionsCancelOrEnter(okToSelect); if (!okToSelect) return; // no update status here, as we might delete the status too early. if (d->m_myMoneyView->dirty()) { int answer = askSaveOnClose(); if (answer == KMessageBox::Cancel) return; else if (answer == KMessageBox::Yes) slotFileSave(); } d->closeFile(); } void KMyMoneyApp::slotFileQuit() { // don't modify the status message here as this will prevent quit from working!! // See the beginning of queryClose() and isReady() why. Thomas Baumgart 2005-10-17 bool quitApplication = true; QList memberList = KMainWindow::memberList(); if (!memberList.isEmpty()) { QList::const_iterator w_it = memberList.constBegin(); for (; w_it != memberList.constEnd(); ++w_it) { // only close the window if the closeEvent is accepted. If the user presses Cancel on the saveModified() dialog, // the window and the application stay open. if (!(*w_it)->close()) { quitApplication = false; break; } } } // We will only quit if all windows were processed and not cancelled if (quitApplication) { QCoreApplication::quit(); } } void KMyMoneyApp::slotShowTransactionDetail() { } void KMyMoneyApp::slotHideReconciledTransactions() { KMyMoneyGlobalSettings::setHideReconciledTransactions(actionCollection()->action(s_Actions[Action::ViewHideReconciled])->isChecked()); d->m_myMoneyView->slotRefreshViews(); } void KMyMoneyApp::slotHideUnusedCategories() { KMyMoneyGlobalSettings::setHideUnusedCategory(actionCollection()->action(s_Actions[Action::ViewHideCategories])->isChecked()); d->m_myMoneyView->slotRefreshViews(); } void KMyMoneyApp::slotShowAllAccounts() { d->m_myMoneyView->slotRefreshViews(); } #ifdef KMM_DEBUG void KMyMoneyApp::slotToggleTraces() { MyMoneyTracer::onOff(actionCollection()->action(s_Actions[Action::DebugTraces])->isChecked() ? 1 : 0); } #endif void KMyMoneyApp::slotToggleTimers() { extern bool timersOn; // main.cpp timersOn = actionCollection()->action(s_Actions[Action::DebugTimers])->isChecked(); } QString KMyMoneyApp::slotStatusMsg(const QString &text) { /////////////////////////////////////////////////////////////////// // change status message permanently QString previousMessage = d->m_statusLabel->text(); d->m_applicationIsReady = false; QString currentMessage = text; if (currentMessage.isEmpty() || currentMessage == i18nc("Application is ready to use", "Ready.")) { d->m_applicationIsReady = true; currentMessage = i18nc("Application is ready to use", "Ready."); } statusBar()->clearMessage(); d->m_statusLabel->setText(currentMessage); return previousMessage; } void KMyMoneyApp::ready() { slotStatusMsg(QString()); } bool KMyMoneyApp::isReady() { return d->m_applicationIsReady; } void KMyMoneyApp::slotStatusProgressBar(int current, int total) { if (total == -1 && current == -1) { // reset if (d->m_progressTimer) { d->m_progressTimer->start(500); // remove from screen in 500 msec d->m_progressBar->setValue(d->m_progressBar->maximum()); } } else if (total != 0) { // init d->m_progressTimer->stop(); d->m_progressBar->setMaximum(total); d->m_progressBar->setValue(0); d->m_progressBar->show(); } else { // update QTime currentTime = QTime::currentTime(); // only process painting if last update is at least 250 ms ago if (abs(d->m_lastUpdate.msecsTo(currentTime)) > 250) { d->m_progressBar->setValue(current); d->m_lastUpdate = currentTime; } } } void KMyMoneyApp::slotStatusProgressDone() { d->m_progressTimer->stop(); d->m_progressBar->reset(); d->m_progressBar->hide(); d->m_progressBar->setValue(0); } void KMyMoneyApp::progressCallback(int current, int total, const QString& msg) { if (!msg.isEmpty()) kmymoney->slotStatusMsg(msg); kmymoney->slotStatusProgressBar(current, total); } void KMyMoneyApp::slotFileViewPersonal() { if (!d->m_myMoneyView->fileOpen()) { KMessageBox::information(this, i18n("No KMyMoneyFile open")); return; } KMSTATUS(i18n("Viewing personal data...")); MyMoneyFile* file = MyMoneyFile::instance(); MyMoneyPayee user = file->user(); QPointer editPersonalDataDlg = new EditPersonalDataDlg(user.name(), user.address(), user.city(), user.state(), user.postcode(), user.telephone(), user.email(), this, i18n("Edit Personal Data")); if (editPersonalDataDlg->exec() == QDialog::Accepted && editPersonalDataDlg != 0) { - user.setName(editPersonalDataDlg->userNameText); - user.setAddress(editPersonalDataDlg->userStreetText); - user.setCity(editPersonalDataDlg->userTownText); - user.setState(editPersonalDataDlg->userCountyText); - user.setPostcode(editPersonalDataDlg->userPostcodeText); - user.setTelephone(editPersonalDataDlg->userTelephoneText); - user.setEmail(editPersonalDataDlg->userEmailText); + user.setName(editPersonalDataDlg->userName()); + user.setAddress(editPersonalDataDlg->userStreet()); + user.setCity(editPersonalDataDlg->userTown()); + user.setState(editPersonalDataDlg->userCountry()); + user.setPostcode(editPersonalDataDlg->userPostcode()); + user.setTelephone(editPersonalDataDlg->userTelephone()); + user.setEmail(editPersonalDataDlg->userEmail()); MyMoneyFileTransaction ft; try { file->setUser(user); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::information(this, i18n("Unable to store user information: %1", e.what())); } } delete editPersonalDataDlg; } void KMyMoneyApp::slotFileFileInfo() { if (!d->m_myMoneyView->fileOpen()) { KMessageBox::information(this, i18n("No KMyMoneyFile open")); return; } QFile g("kmymoney.dump"); g.open(QIODevice::WriteOnly); QDataStream st(&g); MyMoneyStorageDump dumper; dumper.writeStream(st, dynamic_cast(MyMoneyFile::instance()->storage())); g.close(); } void KMyMoneyApp::slotLoadAccountTemplates() { KMSTATUS(i18n("Importing account templates.")); int rc; QPointer dlg = new KLoadTemplateDlg(); if ((rc = dlg->exec()) == QDialog::Accepted && dlg != 0) { MyMoneyFileTransaction ft; try { // import the account templates QList templates = dlg->templates(); QList::iterator it_t; for (it_t = templates.begin(); it_t != templates.end(); ++it_t) { (*it_t).importTemplate(&progressCallback); } ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to import template(s): %1, thrown in %2:%3", e.what(), e.file(), e.line())); } } delete dlg; } void KMyMoneyApp::slotSaveAccountTemplates() { KMSTATUS(i18n("Exporting account templates.")); QString savePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/templates/" + QLocale().name(); QDir d(savePath); if (!d.exists()) d.mkpath(savePath); QString newName = QFileDialog::getSaveFileName(this, i18n("Save as..."), savePath, i18n("KMyMoney template files (*.kmt);;All files (*)")); // // If there is no file extension, then append a .kmt at the end of the file name. // If there is a file extension, make sure it is .kmt, delete any others. // if (!newName.isEmpty()) { // find last . delimiter int nLoc = newName.lastIndexOf('.'); if (nLoc != -1) { QString strExt, strTemp; strTemp = newName.left(nLoc + 1); strExt = newName.right(newName.length() - (nLoc + 1)); if ((strExt.indexOf("kmt", 0, Qt::CaseInsensitive) == -1)) { strTemp.append("kmt"); //append to make complete file name newName = strTemp; } } else { newName.append(".kmt"); } if (okToWriteFile(QUrl::fromLocalFile(newName))) { QPointer dlg = new KTemplateExportDlg(this); if (dlg->exec() == QDialog::Accepted && dlg) { MyMoneyTemplate templ; templ.setTitle(dlg->title()); templ.setShortDescription(dlg->shortDescription()); templ.setLongDescription(dlg->longDescription()); templ.exportTemplate(&progressCallback); templ.saveTemplate(QUrl::fromLocalFile(newName)); } delete dlg; } } } void KMyMoneyApp::slotGncImport() { if (d->m_myMoneyView->fileOpen()) { switch (KMessageBox::questionYesNoCancel(0, i18n("You cannot import GnuCash data into an existing file. Do you wish to save this file?"), PACKAGE)) { case KMessageBox::Yes: slotFileSave(); break; case KMessageBox::No: d->closeFile(); break; default: return; } } KMSTATUS(i18n("Importing a GnuCash file.")); QUrl fileToRead = QFileDialog::getOpenFileUrl(this, QString(), QUrl(), i18n("GnuCash files (*.gnucash *.xac *.gnc);;All files (*)")); if (!fileToRead.isEmpty()) { // call the importer if (d->m_myMoneyView->readFile(fileToRead)) { // imported files don't have a name d->m_fileName = QUrl(); updateCaption(); emit fileLoaded(d->m_fileName); } } } void KMyMoneyApp::slotAccountChart() { if (!d->m_selectedAccount.id().isEmpty()) { QPointer dlg = new KBalanceChartDlg(d->m_selectedAccount, this); dlg->exec(); delete dlg; } } // // KMyMoneyApp::slotStatementImport() is for testing only. The MyMoneyStatement // is not intended to be exposed to users in XML form. // void KMyMoneyApp::slotStatementImport() { bool result = false; KMSTATUS(i18n("Importing an XML Statement.")); QList files{QFileDialog::getOpenFileUrls(this, QString(), QUrl(), i18n("XML files (*.xml);;All files (*)"))}; if (!files.isEmpty()) { d->m_collectingStatements = (files.count() > 1); foreach (const QUrl &url, files) { qDebug("Processing '%s'", qPrintable(url.path())); result |= slotStatementImport(url.path()); } /* QFile f( dialog->selectedURL().path() ); f.open( QIODevice::ReadOnly ); QString error = "Unable to parse file"; QDomDocument* doc = new QDomDocument; if(doc->setContent(&f, FALSE)) { if ( doc->doctype().name() == "KMYMONEY-STATEMENT" ) { QDomElement rootElement = doc->documentElement(); if(!rootElement.isNull()) { QDomNode child = rootElement.firstChild(); if(!child.isNull() && child.isElement()) { MyMoneyStatement s; if ( s.read(child.toElement()) ) result = slotStatementImport(s); else error = "File does not contain any statements"; } } } else error = "File is not a KMyMoney Statement"; } delete doc; if ( !result ) { QMessageBox::critical( this, i18n("Critical Error"), i18n("Unable to read file %1: %2").arg( dialog->selectedURL().path()).arg(error), QMessageBox::Ok, 0 ); }*/ } if (!result) { // re-enable all standard widgets setEnabled(true); } } bool KMyMoneyApp::slotStatementImport(const QString& url) { bool result = false; MyMoneyStatement s; if (MyMoneyStatement::readXMLFile(s, url)) result = slotStatementImport(s); else KMessageBox::error(this, i18n("Error importing %1: This file is not a valid KMM statement file.", url), i18n("Invalid Statement")); return result; } bool KMyMoneyApp::slotStatementImport(const MyMoneyStatement& s, bool silent) { bool result = false; // keep a copy of the statement if (KMyMoneySettings::logImportedStatements()) { QString logFile = QString("%1/kmm-statement-%2.txt").arg(KMyMoneySettings::logPath()).arg(d->m_statementXMLindex++); MyMoneyStatement::writeXMLFile(s, logFile); } // we use an object on the heap here, so that we can check the presence // of it during slotUpdateActions() by looking at the pointer. d->m_smtReader = new MyMoneyStatementReader; d->m_smtReader->setAutoCreatePayee(true); d->m_smtReader->setProgressCallback(&progressCallback); // disable all standard widgets during the import setEnabled(false); QStringList messages; result = d->m_smtReader->import(s, messages); bool transactionAdded = d->m_smtReader->anyTransactionAdded(); // get rid of the statement reader and tell everyone else // about the destruction by setting the pointer to zero delete d->m_smtReader; d->m_smtReader = 0; slotStatusProgressBar(-1, -1); ready(); // re-enable all standard widgets setEnabled(true); if (!d->m_collectingStatements && !silent) KMessageBox::informationList(this, i18n("The statement has been processed with the following results:"), messages, i18n("Statement stats")); else if (transactionAdded) d->m_statementResults += messages; slotUpdateActions();// Re-enable menu items after import via plugin. return result; } bool KMyMoneyApp::okToWriteFile(const QUrl &url) { Q_UNUSED(url) // check if the file exists and warn the user bool reallySaveFile = true; // TODO: port KF5 (NetAccess) //if (KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, this)) { // if (KMessageBox::warningYesNo(this, QLatin1String("") + i18n("The file %1 already exists. Do you really want to overwrite it?", url.toDisplayString(QUrl::PreferLocalFile)) + QLatin1String(""), i18n("File already exists")) != KMessageBox::Yes) // reallySaveFile = false; //} return reallySaveFile; } void KMyMoneyApp::slotSettings() { // if we already have an instance of the settings dialog, then use it if (KConfigDialog::showDialog("KMyMoney-Settings")) return; // otherwise, we have to create it KConfigDialog* dlg = new KSettingsKMyMoney(this, "KMyMoney-Settings", KMyMoneyGlobalSettings::self()); connect(dlg, &KConfigDialog::settingsChanged, this, &KMyMoneyApp::slotUpdateConfiguration); dlg->show(); } void KMyMoneyApp::slotShowCredits() { KAboutData aboutData = initializeCreditsData(); KAboutApplicationDialog dlg(aboutData, this); dlg.exec(); } void KMyMoneyApp::slotUpdateConfiguration() { MyMoneyTransactionFilter::setFiscalYearStart(KMyMoneyGlobalSettings::firstFiscalMonth(), KMyMoneyGlobalSettings::firstFiscalDay()); LedgerSeperator::setFirstFiscalDate(KMyMoneyGlobalSettings::firstFiscalMonth(), KMyMoneyGlobalSettings::firstFiscalDay()); d->m_myMoneyView->updateViewType(); // update the sql storage module settings MyMoneyStorageSql::setStartDate(KMyMoneyGlobalSettings::startDate().date()); // update the report module settings MyMoneyReport::setLineWidth(KMyMoneyGlobalSettings::lineWidth()); // update the holiday region configuration setHolidayRegion(KMyMoneyGlobalSettings::holidayRegion()); d->m_myMoneyView->slotRefreshViews(); // re-read autosave configuration d->m_autoSaveEnabled = KMyMoneyGlobalSettings::autoSaveFile(); d->m_autoSavePeriod = KMyMoneyGlobalSettings::autoSavePeriod(); // stop timer if turned off but running if (d->m_autoSaveTimer->isActive() && !d->m_autoSaveEnabled) { d->m_autoSaveTimer->stop(); } // start timer if turned on and needed but not running if (!d->m_autoSaveTimer->isActive() && d->m_autoSaveEnabled && d->m_myMoneyView->dirty()) { d->m_autoSaveTimer->setSingleShot(true); d->m_autoSaveTimer->start(d->m_autoSavePeriod * 60 * 1000); } d->setThemedCSS(); // check if the recovery key is still valid or expires soon if (KMyMoneySettings::writeDataEncrypted() && KMyMoneySettings::encryptRecover()) { if (KGPGFile::GPGAvailable()) { KGPGFile file; QDateTime expirationDate = file.keyExpires(QLatin1String(recoveryKeyId)); if (expirationDate.isValid() && QDateTime::currentDateTime().daysTo(expirationDate) <= RECOVER_KEY_EXPIRATION_WARNING) { bool skipMessage = false; //get global config object for our app. KSharedConfigPtr kconfig = KSharedConfig::openConfig(); KConfigGroup grp; QDate lastWarned; if (kconfig) { grp = d->m_config->group("General Options"); lastWarned = grp.readEntry("LastRecoverKeyExpirationWarning", QDate()); if (QDate::currentDate() == lastWarned) { skipMessage = true; } } if (!skipMessage) { if (kconfig) { grp.writeEntry("LastRecoverKeyExpirationWarning", QDate::currentDate()); } KMessageBox::information(this, i18np("You have configured KMyMoney to use GPG to protect your data and to encrypt your data also with the KMyMoney recover key. This key is about to expire in %1 day. Please update the key from a keyserver using your GPG frontend (e.g. KGPG).", "You have configured KMyMoney to use GPG to protect your data and to encrypt your data also with the KMyMoney recover key. This key is about to expire in %1 days. Please update the key from a keyserver using your GPG frontend (e.g. KGPG).", QDateTime::currentDateTime().daysTo(expirationDate)), i18n("Recover key expires soon")); } } } } } void KMyMoneyApp::slotBackupFile() { // Save the file first so isLocalFile() works if (d->m_myMoneyView && d->m_myMoneyView->dirty()) { if (KMessageBox::questionYesNo(this, i18n("The file must be saved first " "before it can be backed up. Do you want to continue?")) == KMessageBox::No) { return; } slotFileSave(); } if (d->m_fileName.isEmpty()) return; if (!d->m_fileName.isLocalFile()) { KMessageBox::sorry(this, i18n("The current implementation of the backup functionality only supports local files as source files. Your current source file is '%1'.", d->m_fileName.url()), i18n("Local files only")); return; } QPointer backupDlg = new KBackupDlg(this); #ifdef Q_OS_WIN backupDlg->mountCheckBox->setEnabled(false); #endif int returncode = backupDlg->exec(); if (returncode == QDialog::Accepted && backupDlg != 0) { - d->m_backupMount = backupDlg->mountCheckBox->isChecked(); + + d->m_backupMount = backupDlg->mountCheckBox(); d->m_proc.clearProgram(); d->m_backupState = BACKUP_MOUNTING; - d->m_mountpoint = backupDlg->txtMountPoint->text(); + d->m_mountpoint = backupDlg->mountPoint(); if (d->m_backupMount) { slotBackupMount(); } else { progressCallback(0, 300, ""); #ifdef Q_OS_WIN d->m_ignoreBackupExitCode = true; QTimer::singleShot(0, this, SLOT(slotBackupHandleEvents())); #else // If we don't have to mount a device, we just issue // a dummy command to start the copy operation d->m_proc.setProgram("true"); d->m_proc.start(); #endif } } delete backupDlg; } void KMyMoneyApp::slotBackupMount() { progressCallback(0, 300, i18n("Mounting %1", d->m_mountpoint)); d->m_proc.setProgram("mount"); d->m_proc << d->m_mountpoint; d->m_proc.start(); } bool KMyMoneyApp::slotBackupWriteFile() { QFileInfo fi(d->m_fileName.fileName()); QString today = QDate::currentDate().toString("-yyyy-MM-dd.") + fi.suffix(); QString backupfile = d->m_mountpoint + '/' + d->m_fileName.fileName(); KMyMoneyUtils::appendCorrectFileExt(backupfile, today); // check if file already exists and ask what to do QFile f(backupfile); if (f.exists()) { int answer = KMessageBox::warningContinueCancel(this, i18n("Backup file for today exists on that device. Replace?"), i18n("Backup"), KGuiItem(i18n("&Replace"))); if (answer == KMessageBox::Cancel) { return false; } } progressCallback(50, 0, i18n("Writing %1", backupfile)); d->m_proc.clearProgram(); #ifdef Q_OS_WIN d->m_proc << "cmd.exe" << "/c" << "copy" << "/b" << "/y"; d->m_proc << (QDir::toNativeSeparators(d->m_fileName.toLocalFile()) + "+ nul") << QDir::toNativeSeparators(backupfile); #else d->m_proc << "cp" << "-f"; d->m_proc << d->m_fileName.toLocalFile() << backupfile; #endif d->m_backupState = BACKUP_COPYING; d->m_proc.start(); return true; } void KMyMoneyApp::slotBackupUnmount() { progressCallback(250, 0, i18n("Unmounting %1", d->m_mountpoint)); d->m_proc.clearProgram(); d->m_proc.setProgram("umount"); d->m_proc << d->m_mountpoint; d->m_backupState = BACKUP_UNMOUNTING; d->m_proc.start(); } void KMyMoneyApp::slotBackupFinish() { d->m_backupState = BACKUP_IDLE; progressCallback(-1, -1, QString()); ready(); } void KMyMoneyApp::slotBackupHandleEvents() { switch (d->m_backupState) { case BACKUP_MOUNTING: if (d->m_ignoreBackupExitCode || (d->m_proc.exitStatus() == QProcess::NormalExit && d->m_proc.exitCode() == 0)) { d->m_ignoreBackupExitCode = false; d->m_backupResult = 0; if (!slotBackupWriteFile()) { d->m_backupResult = 1; if (d->m_backupMount) slotBackupUnmount(); else slotBackupFinish(); } } else { KMessageBox::information(this, i18n("Error mounting device"), i18n("Backup")); d->m_backupResult = 1; if (d->m_backupMount) slotBackupUnmount(); else slotBackupFinish(); } break; case BACKUP_COPYING: if (d->m_proc.exitStatus() == QProcess::NormalExit && d->m_proc.exitCode() == 0) { if (d->m_backupMount) { slotBackupUnmount(); } else { progressCallback(300, 0, i18nc("Backup done", "Done")); KMessageBox::information(this, i18n("File successfully backed up"), i18n("Backup")); slotBackupFinish(); } } else { qDebug("copy exit code is %d", d->m_proc.exitCode()); d->m_backupResult = 1; KMessageBox::information(this, i18n("Error copying file to device"), i18n("Backup")); if (d->m_backupMount) slotBackupUnmount(); else slotBackupFinish(); } break; case BACKUP_UNMOUNTING: if (d->m_proc.exitStatus() == QProcess::NormalExit && d->m_proc.exitCode() == 0) { progressCallback(300, 0, i18nc("Backup done", "Done")); if (d->m_backupResult == 0) KMessageBox::information(this, i18n("File successfully backed up"), i18n("Backup")); } else { KMessageBox::information(this, i18n("Error unmounting device"), i18n("Backup")); } slotBackupFinish(); break; default: qWarning("Unknown state for backup operation!"); progressCallback(-1, -1, QString()); ready(); break; } } void KMyMoneyApp::slotShowTipOfTheDay() { KTipDialog::showTip(d->m_myMoneyView, "", true); } void KMyMoneyApp::slotShowPreviousView() { } void KMyMoneyApp::slotShowNextView() { } void KMyMoneyApp::slotGenerateSql() { QPointer editor = new KGenerateSqlDlg(this); editor->setObjectName("Generate Database SQL"); editor->exec(); delete editor; } void KMyMoneyApp::slotToolsStartKCalc() { QString cmd = KMyMoneyGlobalSettings::externalCalculator(); // if none is present, we fall back to the default if (cmd.isEmpty()) { #if defined(Q_OS_WIN32) cmd = QLatin1String("calc"); #elif defined(Q_OS_MAC) cmd = QLatin1String("open -a Calculator"); #else cmd = QLatin1String("kcalc"); #endif } KRun::runCommand(cmd, this); } void KMyMoneyApp::slotFindTransaction() { if (d->m_searchDlg == 0) { d->m_searchDlg = new KFindTransactionDlg(this); connect(d->m_searchDlg, SIGNAL(destroyed()), this, SLOT(slotCloseSearchDialog())); connect(d->m_searchDlg, SIGNAL(transactionSelected(QString,QString)), d->m_myMoneyView, SLOT(slotLedgerSelected(QString,QString))); } d->m_searchDlg->show(); d->m_searchDlg->raise(); d->m_searchDlg->activateWindow(); } void KMyMoneyApp::slotCloseSearchDialog() { if (d->m_searchDlg) d->m_searchDlg->deleteLater(); d->m_searchDlg = 0; } void KMyMoneyApp::createInstitution(MyMoneyInstitution& institution) { MyMoneyFile* file = MyMoneyFile::instance(); MyMoneyFileTransaction ft; try { file->addInstitution(institution); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::information(this, i18n("Cannot add institution: %1", e.what())); } } void KMyMoneyApp::slotInstitutionNew() { MyMoneyInstitution institution; slotInstitutionNew(institution); } void KMyMoneyApp::slotInstitutionNew(MyMoneyInstitution& institution) { institution.clearId(); QPointer dlg = new KNewBankDlg(institution); if (dlg->exec() == QDialog::Accepted && dlg != 0) { institution = dlg->institution(); createInstitution(institution); } delete dlg; } void KMyMoneyApp::slotInstitutionEditEmpty() { slotInstitutionEdit(MyMoneyInstitution()); } void KMyMoneyApp::slotInstitutionEdit(const MyMoneyObject& obj) { if (typeid(obj) != typeid(MyMoneyInstitution)) return; // make sure the selected object has an id if (d->m_selectedInstitution.id().isEmpty()) return; try { MyMoneyFile* file = MyMoneyFile::instance(); //grab a pointer to the view, regardless of it being a account or institution view. MyMoneyInstitution institution = file->institution(d->m_selectedInstitution.id()); // bankSuccess is not checked anymore because d->m_file->institution will throw anyway QPointer dlg = new KNewBankDlg(institution); if (dlg->exec() == QDialog::Accepted && dlg != 0) { MyMoneyFileTransaction ft; try { file->modifyInstitution(dlg->institution()); ft.commit(); slotSelectInstitution(file->institution(dlg->institution().id())); } catch (const MyMoneyException &e) { KMessageBox::information(this, i18n("Unable to store institution: %1", e.what())); } } delete dlg; } catch (const MyMoneyException &e) { if (!obj.id().isEmpty()) KMessageBox::information(this, i18n("Unable to edit institution: %1", e.what())); } } void KMyMoneyApp::slotInstitutionDelete() { MyMoneyFile *file = MyMoneyFile::instance(); try { MyMoneyInstitution institution = file->institution(d->m_selectedInstitution.id()); if ((KMessageBox::questionYesNo(this, i18n("

Do you really want to delete the institution %1?

", institution.name()))) == KMessageBox::No) return; MyMoneyFileTransaction ft; try { file->removeInstitution(institution); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::information(this, i18n("Unable to delete institution: %1", e.what())); } } catch (const MyMoneyException &e) { KMessageBox::information(this, i18n("Unable to delete institution: %1", e.what())); } } void KMyMoneyApp::createAccount(MyMoneyAccount& newAccount, MyMoneyAccount& parentAccount, MyMoneyAccount& brokerageAccount, MyMoneyMoney openingBal) { MyMoneyFile *file = MyMoneyFile::instance(); try { const MyMoneySecurity& sec = file->security(newAccount.currencyId()); // Check the opening balance if (openingBal.isPositive() && newAccount.accountGroup() == eMyMoney::Account::Liability) { QString message = i18n("This account is a liability and if the " "opening balance represents money owed, then it should be negative. " "Negate the amount?\n\n" "Please click Yes to change the opening balance to %1,\n" "Please click No to leave the amount as %2,\n" "Please click Cancel to abort the account creation." , MyMoneyUtils::formatMoney(-openingBal, newAccount, sec) , MyMoneyUtils::formatMoney(openingBal, newAccount, sec)); int ans = KMessageBox::questionYesNoCancel(this, message); if (ans == KMessageBox::Yes) { openingBal = -openingBal; } else if (ans == KMessageBox::Cancel) return; } file->createAccount(newAccount, parentAccount, brokerageAccount, openingBal); } catch (const MyMoneyException &e) { KMessageBox::information(this, i18n("Unable to add account: %1", e.what())); } } void KMyMoneyApp::slotCategoryNew(const QString& name, QString& id) { MyMoneyAccount account; account.setName(name); slotCategoryNew(account, MyMoneyFile::instance()->expense()); id = account.id(); } void KMyMoneyApp::slotCategoryNew(MyMoneyAccount& account, const MyMoneyAccount& parent) { if (KMessageBox::questionYesNo(this, QString("%1").arg(i18n("

The category %1 currently does not exist. Do you want to create it?

The parent account will default to %2 but can be changed in the following dialog.

", account.name(), parent.name())), i18n("Create category"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "CreateNewCategories") == KMessageBox::Yes) { createCategory(account, parent); } else { // we should not keep the 'no' setting because that can confuse people like // I have seen in some usability tests. So we just delete it right away. KSharedConfigPtr kconfig = KSharedConfig::openConfig(); if (kconfig) { kconfig->group(QLatin1String("Notification Messages")).deleteEntry(QLatin1String("CreateNewCategories")); } } } void KMyMoneyApp::slotCategoryNew(MyMoneyAccount& account) { slotCategoryNew(account, MyMoneyAccount()); } void KMyMoneyApp::slotCategoryNew() { MyMoneyAccount parent; MyMoneyAccount account; // Preselect the parent account by looking at the current selected account/category if (!d->m_selectedAccount.id().isEmpty() && d->m_selectedAccount.isIncomeExpense()) { MyMoneyFile* file = MyMoneyFile::instance(); try { parent = file->account(d->m_selectedAccount.id()); } catch (const MyMoneyException &) { } } createCategory(account, parent); } void KMyMoneyApp::createCategory(MyMoneyAccount& account, const MyMoneyAccount& parent) { if (!parent.id().isEmpty()) { try { // make sure parent account exists MyMoneyFile::instance()->account(parent.id()); account.setParentAccountId(parent.id()); account.setAccountType(parent.accountType()); } catch (const MyMoneyException &) { } } QPointer dialog = new KNewAccountDlg(account, false, true, 0, i18n("Create a new Category")); dialog->setOpeningBalanceShown(false); dialog->setOpeningDateShown(false); if (dialog->exec() == QDialog::Accepted && dialog != 0) { MyMoneyAccount parentAccount, brokerageAccount; account = dialog->account(); parentAccount = dialog->parentAccount(); MyMoneyFile::instance()->createAccount(account, parentAccount, brokerageAccount, MyMoneyMoney()); } delete dialog; } void KMyMoneyApp::slotAccountNew() { MyMoneyAccount acc; acc.setInstitutionId(d->m_selectedInstitution.id()); acc.setOpeningDate(KMyMoneyGlobalSettings::firstFiscalDate()); slotAccountNew(acc); } void KMyMoneyApp::slotAccountNew(MyMoneyAccount& account) { NewAccountWizard::Wizard* wizard = new NewAccountWizard::Wizard(); connect(wizard, SIGNAL(createInstitution(MyMoneyInstitution&)), this, SLOT(slotInstitutionNew(MyMoneyInstitution&))); connect(wizard, SIGNAL(createAccount(MyMoneyAccount&)), this, SLOT(slotAccountNew(MyMoneyAccount&))); connect(wizard, SIGNAL(createPayee(QString,QString&)), this, SLOT(slotPayeeNew(QString,QString&))); connect(wizard, SIGNAL(createCategory(MyMoneyAccount&,MyMoneyAccount)), this, SLOT(slotCategoryNew(MyMoneyAccount&,MyMoneyAccount))); wizard->setAccount(account); if (wizard->exec() == QDialog::Accepted) { MyMoneyAccount acc = wizard->account(); if (!(acc == MyMoneyAccount())) { MyMoneyFileTransaction ft; MyMoneyFile* file = MyMoneyFile::instance(); try { // create the account MyMoneyAccount parent = wizard->parentAccount(); file->addAccount(acc, parent); // tell the wizard about the account id which it // needs to create a possible schedule and transactions wizard->setAccount(acc); // store a possible conversion rate for the currency if (acc.currencyId() != file->baseCurrency().id()) { file->addPrice(wizard->conversionRate()); } // create the opening balance transaction if any file->createOpeningBalanceTransaction(acc, wizard->openingBalance()); // create the payout transaction for loans if any MyMoneyTransaction payoutTransaction = wizard->payoutTransaction(); if (payoutTransaction.splits().count() > 0) { file->addTransaction(payoutTransaction); } // create a brokerage account if selected MyMoneyAccount brokerageAccount = wizard->brokerageAccount(); if (!(brokerageAccount == MyMoneyAccount())) { file->addAccount(brokerageAccount, parent); } // create a possible schedule MyMoneySchedule sch = wizard->schedule(); if (!(sch == MyMoneySchedule())) { MyMoneyFile::instance()->addSchedule(sch); if (acc.isLoan()) { MyMoneyAccountLoan accLoan = MyMoneyFile::instance()->account(acc.id()); accLoan.setSchedule(sch.id()); acc = accLoan; MyMoneyFile::instance()->modifyAccount(acc); } } ft.commit(); account = acc; } catch (const MyMoneyException &e) { KMessageBox::error(this, i18n("Unable to create account: %1", e.what())); } } } delete wizard; } void KMyMoneyApp::slotInvestmentNew(MyMoneyAccount& account, const MyMoneyAccount& parent) { QString dontShowAgain = "CreateNewInvestments"; if (KMessageBox::questionYesNo(this, QString("") + i18n("The security %1 currently does not exist as sub-account of %2. " "Do you want to create it?", account.name(), parent.name()) + QString(""), i18n("Create security"), KStandardGuiItem::yes(), KStandardGuiItem::no(), dontShowAgain) == KMessageBox::Yes) { KNewInvestmentWizard dlg; dlg.setName(account.name()); if (dlg.exec() == QDialog::Accepted) { dlg.createObjects(parent.id()); account = dlg.account(); } } else { // in case the user said no but turned on the don't show again selection, we will enable // the message no matter what. Otherwise, the user is not able to use this feature // in the future anymore. KMessageBox::enableMessage(dontShowAgain); } } void KMyMoneyApp::slotInvestmentNew() { QPointer dlg = new KNewInvestmentWizard(this); if (dlg->exec() == QDialog::Accepted) dlg->createObjects(d->m_selectedAccount.id()); delete dlg; } void KMyMoneyApp::slotInvestmentEdit() { QPointer dlg = new KNewInvestmentWizard(d->m_selectedInvestment); if (dlg->exec() == QDialog::Accepted) dlg->createObjects(d->m_selectedAccount.id()); delete dlg; } void KMyMoneyApp::slotInvestmentDelete() { if (KMessageBox::questionYesNo(this, i18n("

Do you really want to delete the investment %1?

", d->m_selectedInvestment.name()), i18n("Delete investment"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "DeleteInvestment") == KMessageBox::Yes) { MyMoneyFile* file = MyMoneyFile::instance(); MyMoneyFileTransaction ft; try { d->m_selectedAccount = MyMoneyAccount(); // CAUTION: deleting equity from investments view needs this, if ID of the equity to be deleted is the smallest from all file->removeAccount(d->m_selectedInvestment); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::information(this, i18n("Unable to delete investment: %1", e.what())); } } else { // we should not keep the 'no' setting because that can confuse people like // I have seen in some usability tests. So we just delete it right away. KSharedConfigPtr kconfig = KSharedConfig::openConfig(); if (kconfig) { kconfig->group(QLatin1String("Notification Messages")).deleteEntry(QLatin1String("DeleteInvestment")); } } } void KMyMoneyApp::slotOnlinePriceUpdate() { if (!d->m_selectedInvestment.id().isEmpty()) { QPointer dlg = new KEquityPriceUpdateDlg(0, d->m_selectedInvestment.currencyId()); if (dlg->exec() == QDialog::Accepted && dlg != 0) { dlg->storePrices(); } delete dlg; } } void KMyMoneyApp::slotManualPriceUpdate() { if (!d->m_selectedInvestment.id().isEmpty()) { try { MyMoneySecurity security = MyMoneyFile::instance()->security(d->m_selectedInvestment.currencyId()); MyMoneySecurity currency = MyMoneyFile::instance()->security(security.tradingCurrency()); const MyMoneyPrice &price = MyMoneyFile::instance()->price(security.id(), currency.id()); QPointer calc = new KCurrencyCalculator(security, currency, MyMoneyMoney::ONE, price.rate(currency.id()), price.date(), MyMoneyMoney::precToDenom(security.pricePrecision())); calc->setupPriceEditor(); // The dialog takes care of adding the price if necessary calc->exec(); delete calc; } catch (const MyMoneyException &e) { qDebug("Error in price update: %s", qPrintable(e.what())); } } } void KMyMoneyApp::createSchedule(MyMoneySchedule newSchedule, MyMoneyAccount& newAccount) { MyMoneyFile* file = MyMoneyFile::instance(); // Add the schedule only if one exists // // Remember to modify the first split to reference the newly created account if (!newSchedule.name().isEmpty()) { try { // We assume at least 2 splits in the transaction MyMoneyTransaction t = newSchedule.transaction(); if (t.splitCount() < 2) { throw MYMONEYEXCEPTION("Transaction for schedule has less than 2 splits!"); } MyMoneyFileTransaction ft; try { file->addSchedule(newSchedule); // in case of a loan account, we keep a reference to this // schedule in the account if (newAccount.accountType() == eMyMoney::Account::Loan || newAccount.accountType() == eMyMoney::Account::AssetLoan) { newAccount.setValue("schedule", newSchedule.id()); file->modifyAccount(newAccount); } ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::information(this, i18n("Unable to add scheduled transaction: %1", e.what())); } } catch (const MyMoneyException &e) { KMessageBox::information(this, i18n("Unable to add scheduled transaction: %1", e.what())); } } } void KMyMoneyApp::slotAccountDelete() { if (d->m_selectedAccount.id().isEmpty()) return; // need an account ID MyMoneyFile* file = MyMoneyFile::instance(); // can't delete standard accounts or account which still have transactions assigned if (file->isStandardAccount(d->m_selectedAccount.id())) return; // check if the account is referenced by a transaction or schedule QBitArray skip((int)eStorage::Reference::Count); skip.fill(false); skip.setBit((int)eStorage::Reference::Account); skip.setBit((int)eStorage::Reference::Institution); skip.setBit((int)eStorage::Reference::Payee); skip.setBit((int)eStorage::Reference::Tag); skip.setBit((int)eStorage::Reference::Security); skip.setBit((int)eStorage::Reference::Currency); skip.setBit((int)eStorage::Reference::Price); bool hasReference = file->isReferenced(d->m_selectedAccount, skip); // make sure we only allow transactions in a 'category' (income/expense account) switch (d->m_selectedAccount.accountType()) { case eMyMoney::Account::Income: case eMyMoney::Account::Expense: break; default: // if the account is still referenced if (hasReference) { return; } break; } // if we get here and still have transactions referencing the account, we // need to check with the user to possibly re-assign them to a different account bool needAskUser = true; bool exit = false; MyMoneyFileTransaction ft; if (hasReference) { // show transaction reassignment dialog needAskUser = false; KCategoryReassignDlg* dlg = new KCategoryReassignDlg(this); QString categoryId = dlg->show(d->m_selectedAccount); delete dlg; // and kill the dialog if (categoryId.isEmpty()) return; // the user aborted the dialog, so let's abort as well MyMoneyAccount newCategory = file->account(categoryId); try { { KMSTATUS(i18n("Adjusting transactions...")); /* d->m_selectedAccount.id() is the old id, categoryId the new one Now search all transactions and schedules that reference d->m_selectedAccount.id() and replace that with categoryId. */ // get the list of all transactions that reference the old account MyMoneyTransactionFilter filter(d->m_selectedAccount.id()); filter.setReportAllSplits(false); QList tlist; QList::iterator it_t; file->transactionList(tlist, filter); slotStatusProgressBar(0, tlist.count()); int cnt = 0; for (it_t = tlist.begin(); it_t != tlist.end(); ++it_t) { slotStatusProgressBar(++cnt, 0); MyMoneyTransaction t = (*it_t); if (t.replaceId(categoryId, d->m_selectedAccount.id())) file->modifyTransaction(t); } slotStatusProgressBar(tlist.count(), 0); } // now fix all schedules { KMSTATUS(i18n("Adjusting scheduled transactions...")); QList slist = file->scheduleList(d->m_selectedAccount.id()); QList::iterator it_s; int cnt = 0; slotStatusProgressBar(0, slist.count()); for (it_s = slist.begin(); it_s != slist.end(); ++it_s) { slotStatusProgressBar(++cnt, 0); MyMoneySchedule sch = (*it_s); if (sch.replaceId(categoryId, d->m_selectedAccount.id())) { file->modifySchedule(sch); } } slotStatusProgressBar(slist.count(), 0); } // now fix all budgets { KMSTATUS(i18n("Adjusting budgets...")); QList blist = file->budgetList(); QList::const_iterator it_b; for (it_b = blist.constBegin(); it_b != blist.constEnd(); ++it_b) { if ((*it_b).hasReferenceTo(d->m_selectedAccount.id())) { MyMoneyBudget b = (*it_b); MyMoneyBudget::AccountGroup fromBudget = b.account(d->m_selectedAccount.id()); MyMoneyBudget::AccountGroup toBudget = b.account(categoryId); toBudget += fromBudget; b.setAccount(toBudget, categoryId); b.removeReference(d->m_selectedAccount.id()); file->modifyBudget(b); } } slotStatusProgressBar(blist.count(), 0); } } catch (MyMoneyException &e) { KMessageBox::error(this, i18n("Unable to exchange category %1 with category %2. Reason: %3", d->m_selectedAccount.name(), newCategory.name(), e.what())); exit = true; } slotStatusProgressBar(-1, -1); } if (exit) return; // retain the account name for a possible later usage in the error message box // since the account removal notifies the views the selected account can be changed // so we make sure by doing this that we display the correct name in the error message QString selectedAccountName = d->m_selectedAccount.name(); // at this point, we must not have a reference to the account // to be deleted anymore switch (d->m_selectedAccount.accountGroup()) { // special handling for categories to allow deleting of empty subcategories case eMyMoney::Account::Income: case eMyMoney::Account::Expense: { // open a compound statement here to be able to declare variables // which would otherwise not work within a case label. // case A - only a single, unused category without subcats selected if (d->m_selectedAccount.accountList().isEmpty()) { if (!needAskUser || (KMessageBox::questionYesNo(this, QString("") + i18n("Do you really want to delete category %1?", selectedAccountName) + QString("")) == KMessageBox::Yes)) { try { file->removeAccount(d->m_selectedAccount); d->m_selectedAccount.clearId(); slotUpdateActions(); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::error(this, QString("") + i18n("Unable to delete category %1. Cause: %2", selectedAccountName, e.what()) + QString("")); } } return; } // case B - we have some subcategories, maybe the user does not want to // delete them all, but just the category itself? MyMoneyAccount parentAccount = file->account(d->m_selectedAccount.parentAccountId()); QStringList accountsToReparent; int result = KMessageBox::questionYesNoCancel(this, QString("") + i18n("Do you want to delete category %1 with all its sub-categories or only " "the category itself? If you only delete the category itself, all its sub-categories " "will be made sub-categories of %2.", selectedAccountName, parentAccount.name()) + QString(""), QString(), KGuiItem(i18n("Delete all")), KGuiItem(i18n("Just the category"))); if (result == KMessageBox::Cancel) return; // cancel pressed? ok, no delete then... // "No" means "Just the category" and that means we need to reparent all subaccounts bool need_confirmation = false; // case C - User only wants to delete the category itself if (result == KMessageBox::No) accountsToReparent = d->m_selectedAccount.accountList(); else { // case D - User wants to delete all subcategories, now check all subcats of // d->m_selectedAccount and remember all that cannot be deleted and // must be "reparented" foreach (const auto accountID, d->m_selectedAccount.accountList()) { // reparent account if a transaction is assigned if (file->transactionCount(accountID) != 0) accountsToReparent.push_back(accountID); else if (!file->account(accountID).accountList().isEmpty()) { // or if we have at least one sub-account that is used for transactions if (!file->hasOnlyUnusedAccounts(file->account(accountID).accountList())) { accountsToReparent.push_back(accountID); //qDebug() << "subaccount not empty"; } } } if (!accountsToReparent.isEmpty()) need_confirmation = true; } if (!accountsToReparent.isEmpty() && need_confirmation) { if (KMessageBox::questionYesNo(this, i18n("

Some sub-categories of category %1 cannot " "be deleted, because they are still used. They will be made sub-categories of %2. Proceed?

", selectedAccountName, parentAccount.name())) != KMessageBox::Yes) { return; // user gets wet feet... } } // all good, now first reparent selected sub-categories try { MyMoneyAccount parent = file->account(d->m_selectedAccount.parentAccountId()); for (QStringList::const_iterator it = accountsToReparent.constBegin(); it != accountsToReparent.constEnd(); ++it) { MyMoneyAccount child = file->account(*it); file->reparentAccount(child, parent); } // reload the account because the sub-account list might have changed d->m_selectedAccount = file->account(d->m_selectedAccount.id()); // now recursively delete remaining sub-categories file->removeAccountList(d->m_selectedAccount.accountList()); // don't forget to update d->m_selectedAccount, because we still have a copy of // the old account list, which is no longer valid d->m_selectedAccount = file->account(d->m_selectedAccount.id()); } catch (const MyMoneyException &e) { KMessageBox::error(this, QString("") + i18n("Unable to delete a sub-category of category %1. Reason: %2", selectedAccountName, e.what()) + QString("")); return; } } break; // the category/account is deleted after the switch default: if (!d->m_selectedAccount.accountList().isEmpty()) return; // can't delete accounts which still have subaccounts if (KMessageBox::questionYesNo(this, i18n("

Do you really want to " "delete account %1?

", selectedAccountName)) != KMessageBox::Yes) { return; // ok, you don't want to? why did you click then, hmm? } } // switch; try { file->removeAccount(d->m_selectedAccount); d->m_selectedAccount.clearId(); slotUpdateActions(); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::error(this, i18n("Unable to delete account '%1'. Cause: %2", selectedAccountName, e.what())); } } void KMyMoneyApp::slotAccountEdit() { MyMoneyFile* file = MyMoneyFile::instance(); if (!d->m_selectedAccount.id().isEmpty()) { if (!file->isStandardAccount(d->m_selectedAccount.id())) { if (d->m_selectedAccount.accountType() != eMyMoney::Account::Loan && d->m_selectedAccount.accountType() != eMyMoney::Account::AssetLoan) { QString caption; bool category = false; switch (d->m_selectedAccount.accountGroup()) { default: caption = i18n("Edit account '%1'", d->m_selectedAccount.name()); break; case eMyMoney::Account::Expense: case eMyMoney::Account::Income: caption = i18n("Edit category '%1'", d->m_selectedAccount.name()); category = true; break; } // set a status message so that the application can't be closed until the editing is done slotStatusMsg(caption); QString tid = file->openingBalanceTransaction(d->m_selectedAccount); MyMoneyTransaction t; MyMoneySplit s0, s1; QPointer dlg = new KNewAccountDlg(d->m_selectedAccount, true, category, 0, caption); if (category) { dlg->setOpeningBalanceShown(false); dlg->setOpeningDateShown(false); tid.clear(); } else { if (!tid.isEmpty()) { try { t = file->transaction(tid); s0 = t.splitByAccount(d->m_selectedAccount.id()); s1 = t.splitByAccount(d->m_selectedAccount.id(), false); dlg->setOpeningBalance(s0.shares()); if (d->m_selectedAccount.accountGroup() == eMyMoney::Account::Liability) { dlg->setOpeningBalance(-s0.shares()); } } catch (const MyMoneyException &e) { qDebug() << "Error retrieving opening balance transaction " << tid << ": " << e.what() << "\n"; tid.clear(); } } } // check for online modules QMap::const_iterator it_plugin = d->m_onlinePlugins.constEnd(); const MyMoneyKeyValueContainer& kvp = d->m_selectedAccount.onlineBankingSettings(); if (!kvp["provider"].isEmpty()) { // if we have an online provider for this account, we need to check // that we have the corresponding plugin. If that exists, we ask it // to provide an additional tab for the account editor. it_plugin = d->m_onlinePlugins.constFind(kvp["provider"]); if (it_plugin != d->m_onlinePlugins.constEnd()) { QString name; QWidget *w = (*it_plugin)->accountConfigTab(d->m_selectedAccount, name); dlg->addTab(w, name); } } if (dlg != 0 && dlg->exec() == QDialog::Accepted) { try { MyMoneyFileTransaction ft; MyMoneyAccount account = dlg->account(); MyMoneyAccount parent = dlg->parentAccount(); if (it_plugin != d->m_onlinePlugins.constEnd()) { account.setOnlineBankingSettings((*it_plugin)->onlineBankingSettings(account.onlineBankingSettings())); } MyMoneyMoney bal = dlg->openingBalance(); if (d->m_selectedAccount.accountGroup() == eMyMoney::Account::Liability) { bal = -bal; } // we need to modify first, as reparent would override all other changes file->modifyAccount(account); if (account.parentAccountId() != parent.id()) { file->reparentAccount(account, parent); } if (!tid.isEmpty() && dlg->openingBalance().isZero()) { file->removeTransaction(t); } else if (!tid.isEmpty() && !dlg->openingBalance().isZero()) { s0.setShares(bal); s0.setValue(bal); t.modifySplit(s0); s1.setShares(-bal); s1.setValue(-bal); t.modifySplit(s1); t.setPostDate(account.openingDate()); file->modifyTransaction(t); } else if (tid.isEmpty() && !dlg->openingBalance().isZero()) { file->createOpeningBalanceTransaction(d->m_selectedAccount, bal); } ft.commit(); // reload the account object as it might have changed in the meantime slotSelectAccount(file->account(account.id())); } catch (const MyMoneyException &e) { KMessageBox::error(this, i18n("Unable to modify account '%1'. Cause: %2", d->m_selectedAccount.name(), e.what())); } } delete dlg; ready(); } else { QPointer wizard = new KEditLoanWizard(d->m_selectedAccount); connect(wizard, SIGNAL(newCategory(MyMoneyAccount&)), this, SLOT(slotCategoryNew(MyMoneyAccount&))); connect(wizard, SIGNAL(createPayee(QString,QString&)), this, SLOT(slotPayeeNew(QString,QString&))); if (wizard->exec() == QDialog::Accepted && wizard != 0) { MyMoneySchedule sch; try { MyMoneySchedule sch = file->schedule(d->m_selectedAccount.value("schedule").toLatin1()); } catch (const MyMoneyException &e) { qDebug() << "schedule" << d->m_selectedAccount.value("schedule").toLatin1() << "not found"; } if (!(d->m_selectedAccount == wizard->account()) || !(sch == wizard->schedule())) { MyMoneyFileTransaction ft; try { file->modifyAccount(wizard->account()); if (!sch.id().isEmpty()) { sch = wizard->schedule(); } try { file->schedule(sch.id()); file->modifySchedule(sch); ft.commit(); } catch (const MyMoneyException &) { try { if(sch.transaction().splitCount() >= 2) { file->addSchedule(sch); } ft.commit(); } catch (const MyMoneyException &e) { qDebug("Cannot add schedule: '%s'", qPrintable(e.what())); } } } catch (const MyMoneyException &e) { qDebug("Unable to modify account %s: '%s'", qPrintable(d->m_selectedAccount.name()), qPrintable(e.what())); } } } delete wizard; } } } } QList > KMyMoneyApp::Private::automaticReconciliation(const MyMoneyAccount &account, const QList > &transactions, const MyMoneyMoney &amount) { static const int NR_OF_STEPS_LIMIT = 300000; static const int PROGRESSBAR_STEPS = 1000; QList > result = transactions; KMSTATUS(i18n("Running automatic reconciliation")); int progressBarIndex = 0; kmymoney->slotStatusProgressBar(progressBarIndex, NR_OF_STEPS_LIMIT / PROGRESSBAR_STEPS); // optimize the most common case - all transactions should be cleared QListIterator > itTransactionSplitResult(result); MyMoneyMoney transactionsBalance; while (itTransactionSplitResult.hasNext()) { const QPair &transactionSplit = itTransactionSplitResult.next(); transactionsBalance += transactionSplit.second.shares(); } if (amount == transactionsBalance) { result = transactions; return result; } kmymoney->slotStatusProgressBar(progressBarIndex++, 0); // only one transaction is uncleared itTransactionSplitResult.toFront(); int index = 0; while (itTransactionSplitResult.hasNext()) { const QPair &transactionSplit = itTransactionSplitResult.next(); if (transactionsBalance - transactionSplit.second.shares() == amount) { result.removeAt(index); return result; } index++; } kmymoney->slotStatusProgressBar(progressBarIndex++, 0); // more than one transaction is uncleared - apply the algorithm result.clear(); const MyMoneySecurity &security = MyMoneyFile::instance()->security(account.currencyId()); double precision = 0.1 / account.fraction(security); QList sumList; sumList << MyMoneyMoney(); QMap > > sumToComponentsMap; // compute the possible matches QListIterator > itTransactionSplit(transactions); while (itTransactionSplit.hasNext()) { const QPair &transactionSplit = itTransactionSplit.next(); QListIterator itSum(sumList); QList tempList; while (itSum.hasNext()) { const MyMoneyMoney &sum = itSum.next(); QList > splitIds; splitIds << qMakePair(transactionSplit.first.id(), transactionSplit.second.id()); if (sumToComponentsMap.contains(sum)) { if (sumToComponentsMap.value(sum).contains(qMakePair(transactionSplit.first.id(), transactionSplit.second.id()))) { continue; } splitIds.append(sumToComponentsMap.value(sum)); } tempList << transactionSplit.second.shares() + sum; sumToComponentsMap[transactionSplit.second.shares() + sum] = splitIds; int size = sumToComponentsMap.size(); if (size % PROGRESSBAR_STEPS == 0) { kmymoney->slotStatusProgressBar(progressBarIndex++, 0); } if (size > NR_OF_STEPS_LIMIT) { return result; // it's taking too much resources abort the algorithm } } QList unionList; unionList.append(tempList); unionList.append(sumList); qSort(unionList); sumList.clear(); MyMoneyMoney smallestSumFromUnion = unionList.first(); sumList.append(smallestSumFromUnion); QListIterator itUnion(unionList); while (itUnion.hasNext()) { MyMoneyMoney sumFromUnion = itUnion.next(); if (smallestSumFromUnion < MyMoneyMoney(1 - precision / transactions.size())*sumFromUnion) { smallestSumFromUnion = sumFromUnion; sumList.append(sumFromUnion); } } } kmymoney->slotStatusProgressBar(NR_OF_STEPS_LIMIT / PROGRESSBAR_STEPS, 0); if (sumToComponentsMap.contains(amount)) { QListIterator > itTransactionSplit(transactions); while (itTransactionSplit.hasNext()) { const QPair &transactionSplit = itTransactionSplit.next(); const QList > &splitIds = sumToComponentsMap.value(amount); if (splitIds.contains(qMakePair(transactionSplit.first.id(), transactionSplit.second.id()))) { result.append(transactionSplit); } } } #ifdef KMM_DEBUG qDebug("For the amount %s a number of %d possible sums where computed from the set of %d transactions: ", qPrintable(MyMoneyUtils::formatMoney(amount, security)), sumToComponentsMap.size(), transactions.size()); #endif kmymoney->slotStatusProgressBar(-1, -1); return result; } void KMyMoneyApp::slotAccountReconcileStart() { MyMoneyFile* file = MyMoneyFile::instance(); MyMoneyAccount account; // we cannot reconcile standard accounts if (!file->isStandardAccount(d->m_selectedAccount.id())) { // check if we can reconcile this account // it make's sense for asset and liability accounts try { // check if we have overdue schedules for this account QList schedules = file->scheduleList(d->m_selectedAccount.id(), eMyMoney::Schedule::Type::Any, eMyMoney::Schedule::Occurrence::Any, eMyMoney::Schedule::PaymentType::Any, QDate(), QDate(), true); if (schedules.count() > 0) { if (KMessageBox::questionYesNo(this, i18n("KMyMoney has detected some overdue scheduled transactions for this account. Do you want to enter those scheduled transactions now?"), i18n("Scheduled transactions found")) == KMessageBox::Yes) { QMap skipMap; bool processedOne; - KMyMoneyUtils::EnterScheduleResultCodeE rc = KMyMoneyUtils::Enter; + eDialogs::ScheduleResultCode rc = eDialogs::ScheduleResultCode::Enter; do { processedOne = false; QList::const_iterator it_sch; - for (it_sch = schedules.constBegin(); (rc != KMyMoneyUtils::Cancel) && (it_sch != schedules.constEnd()); ++it_sch) { + for (it_sch = schedules.constBegin(); (rc != eDialogs::ScheduleResultCode::Cancel) && (it_sch != schedules.constEnd()); ++it_sch) { MyMoneySchedule sch(*(it_sch)); // and enter it if it is not on the skip list if (skipMap.find((*it_sch).id()) == skipMap.end()) { rc = enterSchedule(sch, false, true); - if (rc == KMyMoneyUtils::Ignore) { + if (rc == eDialogs::ScheduleResultCode::Ignore) { skipMap[(*it_sch).id()] = true; } } } // reload list (maybe this schedule needs to be added again) schedules = file->scheduleList(d->m_selectedAccount.id(), eMyMoney::Schedule::Type::Any, eMyMoney::Schedule::Occurrence::Any, eMyMoney::Schedule::PaymentType::Any, QDate(), QDate(), true); } while (processedOne); } } account = file->account(d->m_selectedAccount.id()); // get rid of previous run. delete d->m_endingBalanceDlg; d->m_endingBalanceDlg = new KEndingBalanceDlg(account, this); if (account.isAssetLiability()) { connect(d->m_endingBalanceDlg, SIGNAL(createPayee(QString,QString&)), this, SLOT(slotPayeeNew(QString,QString&))); connect(d->m_endingBalanceDlg, SIGNAL(createCategory(MyMoneyAccount&,MyMoneyAccount)), this, SLOT(slotCategoryNew(MyMoneyAccount&,MyMoneyAccount))); if (d->m_endingBalanceDlg->exec() == QDialog::Accepted) { if (KMyMoneyGlobalSettings::autoReconciliation()) { MyMoneyMoney startBalance = d->m_endingBalanceDlg->previousBalance(); MyMoneyMoney endBalance = d->m_endingBalanceDlg->endingBalance(); QDate endDate = d->m_endingBalanceDlg->statementDate(); QList > transactionList; MyMoneyTransactionFilter filter(account.id()); filter.addState((int)eMyMoney::TransactionFilter::State::Cleared); filter.addState((int)eMyMoney::TransactionFilter::State::NotReconciled); filter.setDateFilter(QDate(), endDate); filter.setConsiderCategory(false); filter.setReportAllSplits(true); file->transactionList(transactionList, filter); QList > result = d->automaticReconciliation(account, transactionList, endBalance - startBalance); if (!result.empty()) { QString message = i18n("KMyMoney has detected transactions matching your reconciliation data.\nWould you like KMyMoney to clear these transactions for you?"); if (KMessageBox::questionYesNo(this, message, i18n("Automatic reconciliation"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "AcceptAutomaticReconciliation") == KMessageBox::Yes) { // mark the transactions cleared KMyMoneyRegister::SelectedTransactions oldSelection = d->m_selectedTransactions; d->m_selectedTransactions.clear(); QListIterator > itTransactionSplitResult(result); while (itTransactionSplitResult.hasNext()) { const QPair &transactionSplit = itTransactionSplitResult.next(); d->m_selectedTransactions.append(KMyMoneyRegister::SelectedTransaction(transactionSplit.first, transactionSplit.second)); } // mark all transactions in d->m_selectedTransactions as 'Cleared' markTransaction(eMyMoney::Split::State::Cleared); d->m_selectedTransactions = oldSelection; } } } if (d->m_myMoneyView->startReconciliation(account, d->m_endingBalanceDlg->statementDate(), d->m_endingBalanceDlg->endingBalance())) { // check if the user requests us to create interest // or charge transactions. MyMoneyTransaction ti = d->m_endingBalanceDlg->interestTransaction(); MyMoneyTransaction tc = d->m_endingBalanceDlg->chargeTransaction(); MyMoneyFileTransaction ft; try { if (ti != MyMoneyTransaction()) { MyMoneyFile::instance()->addTransaction(ti); } if (tc != MyMoneyTransaction()) { MyMoneyFile::instance()->addTransaction(tc); } ft.commit(); } catch (const MyMoneyException &e) { qWarning("interest transaction not stored: '%s'", qPrintable(e.what())); } // reload the account object as it might have changed in the meantime d->m_reconciliationAccount = file->account(account.id()); slotUpdateActions(); } } } } catch (const MyMoneyException &) { } } } void KMyMoneyApp::slotAccountReconcileFinish() { MyMoneyFile* file = MyMoneyFile::instance(); if (!d->m_reconciliationAccount.id().isEmpty()) { // retrieve list of all transactions that are not reconciled or cleared QList > transactionList; MyMoneyTransactionFilter filter(d->m_reconciliationAccount.id()); filter.addState((int)eMyMoney::TransactionFilter::State::Cleared); filter.addState((int)eMyMoney::TransactionFilter::State::NotReconciled); filter.setDateFilter(QDate(), d->m_endingBalanceDlg->statementDate()); filter.setConsiderCategory(false); filter.setReportAllSplits(true); file->transactionList(transactionList, filter); MyMoneyMoney balance = MyMoneyFile::instance()->balance(d->m_reconciliationAccount.id(), d->m_endingBalanceDlg->statementDate()); MyMoneyMoney actBalance, clearedBalance; actBalance = clearedBalance = balance; // walk the list of transactions to figure out the balance(s) QList >::const_iterator it; for (it = transactionList.constBegin(); it != transactionList.constEnd(); ++it) { if ((*it).second.reconcileFlag() == eMyMoney::Split::State::NotReconciled) { clearedBalance -= (*it).second.shares(); } } if (d->m_endingBalanceDlg->endingBalance() != clearedBalance) { QString message = i18n("You are about to finish the reconciliation of this account with a difference between your bank statement and the transactions marked as cleared.\n" "Are you sure you want to finish the reconciliation?"); if (KMessageBox::questionYesNo(this, message, i18n("Confirm end of reconciliation"), KStandardGuiItem::yes(), KStandardGuiItem::no()) == KMessageBox::No) return; } MyMoneyFileTransaction ft; // refresh object d->m_reconciliationAccount = file->account(d->m_reconciliationAccount.id()); // Turn off reconciliation mode d->m_myMoneyView->finishReconciliation(d->m_reconciliationAccount); // only update the last statement balance here, if we haven't a newer one due // to download of online statements. if (d->m_reconciliationAccount.value("lastImportedTransactionDate").isEmpty() || QDate::fromString(d->m_reconciliationAccount.value("lastImportedTransactionDate"), Qt::ISODate) < d->m_endingBalanceDlg->statementDate()) { d->m_reconciliationAccount.setValue("lastStatementBalance", d->m_endingBalanceDlg->endingBalance().toString()); // in case we override the last statement balance here, we have to make sure // that we don't show the online balance anymore, as it might be different d->m_reconciliationAccount.deletePair("lastImportedTransactionDate"); } d->m_reconciliationAccount.setLastReconciliationDate(d->m_endingBalanceDlg->statementDate()); // keep a record of this reconciliation d->m_reconciliationAccount.addReconciliation(d->m_endingBalanceDlg->statementDate(), d->m_endingBalanceDlg->endingBalance()); d->m_reconciliationAccount.deletePair("lastReconciledBalance"); d->m_reconciliationAccount.deletePair("statementBalance"); d->m_reconciliationAccount.deletePair("statementDate"); try { // update the account data file->modifyAccount(d->m_reconciliationAccount); /* // collect the list of cleared splits for this account filter.clear(); filter.addAccount(d->m_reconciliationAccount.id()); filter.addState(eMyMoney::TransactionFilter::Cleared); filter.setConsiderCategory(false); filter.setReportAllSplits(true); file->transactionList(transactionList, filter); */ // walk the list of transactions/splits and mark the cleared ones as reconciled QList >::iterator it; for (it = transactionList.begin(); it != transactionList.end(); ++it) { MyMoneySplit sp = (*it).second; // skip the ones that are not marked cleared if (sp.reconcileFlag() != eMyMoney::Split::State::Cleared) continue; // always retrieve a fresh copy of the transaction because we // might have changed it already with another split MyMoneyTransaction t = file->transaction((*it).first.id()); sp.setReconcileFlag(eMyMoney::Split::State::Reconciled); sp.setReconcileDate(d->m_endingBalanceDlg->statementDate()); t.modifySplit(sp); // update the engine ... file->modifyTransaction(t); // ... and the list (*it) = qMakePair(t, sp); } ft.commit(); // reload account data from engine as the data might have changed in the meantime d->m_reconciliationAccount = file->account(d->m_reconciliationAccount.id()); emit accountReconciled(d->m_reconciliationAccount, d->m_endingBalanceDlg->statementDate(), d->m_endingBalanceDlg->previousBalance(), d->m_endingBalanceDlg->endingBalance(), transactionList); } catch (const MyMoneyException &) { qDebug("Unexpected exception when setting cleared to reconcile"); } } // Turn off reconciliation mode d->m_reconciliationAccount = MyMoneyAccount(); slotUpdateActions(); } void KMyMoneyApp::slotAccountReconcilePostpone() { MyMoneyFileTransaction ft; MyMoneyFile* file = MyMoneyFile::instance(); if (!d->m_reconciliationAccount.id().isEmpty()) { // refresh object d->m_reconciliationAccount = file->account(d->m_reconciliationAccount.id()); // Turn off reconciliation mode d->m_myMoneyView->finishReconciliation(d->m_reconciliationAccount); d->m_reconciliationAccount.setValue("lastReconciledBalance", d->m_endingBalanceDlg->previousBalance().toString()); d->m_reconciliationAccount.setValue("statementBalance", d->m_endingBalanceDlg->endingBalance().toString()); d->m_reconciliationAccount.setValue("statementDate", d->m_endingBalanceDlg->statementDate().toString(Qt::ISODate)); try { file->modifyAccount(d->m_reconciliationAccount); ft.commit(); d->m_reconciliationAccount = MyMoneyAccount(); slotUpdateActions(); } catch (const MyMoneyException &) { qDebug("Unexpected exception when setting last reconcile info into account"); ft.rollback(); d->m_reconciliationAccount = file->account(d->m_reconciliationAccount.id()); } } } void KMyMoneyApp::slotAccountOpenEmpty() { slotAccountOpen(MyMoneyAccount()); } void KMyMoneyApp::slotAccountOpen(const MyMoneyObject& obj) { if (typeid(obj) != typeid(MyMoneyAccount)) return; MyMoneyFile* file = MyMoneyFile::instance(); QString id = d->m_selectedAccount.id(); // if the caller passed a non-empty object, we need to select that if (!obj.id().isEmpty()) { id = obj.id(); } // we cannot reconcile standard accounts if (!file->isStandardAccount(id)) { // check if we can open this account // currently it make's sense for asset and liability accounts try { MyMoneyAccount account = file->account(id); d->m_myMoneyView->slotLedgerSelected(account.id()); } catch (const MyMoneyException &) { } } } void KMyMoneyApp::enableCloseAccountAction(const MyMoneyAccount& acc) { QAction *a = actionCollection()->action(s_Actions[Action::AccountClose]); switch (canCloseAccount(acc)) { case KMyMoneyUtils::AccountCanClose: { a->setEnabled(true); break; } case KMyMoneyUtils::AccountBalanceNonZero: { a->setEnabled(false); a->setToolTip(i18n("The balance of the account must be zero before the account can be closed")); break; } case KMyMoneyUtils::AccountChildrenOpen: { a->setEnabled(false); a->setToolTip(i18n("All subaccounts must be closed before the account can be closed")); break; } case KMyMoneyUtils::AccountScheduleReference: { a->setEnabled(false); a->setToolTip(i18n("This account is still included in an active schedule")); break; } } } KMyMoneyUtils::CanCloseAccountCodeE KMyMoneyApp::canCloseAccount(const MyMoneyAccount& acc) const { // balance must be zero if (!acc.balance().isZero()) return KMyMoneyUtils::AccountBalanceNonZero; // all children must be already closed QStringList::const_iterator it_a; for (it_a = acc.accountList().constBegin(); it_a != acc.accountList().constEnd(); ++it_a) { MyMoneyAccount a = MyMoneyFile::instance()->account(*it_a); if (!a.isClosed()) { return KMyMoneyUtils::AccountChildrenOpen; } } // there must be no unfinished schedule referencing the account QList list = MyMoneyFile::instance()->scheduleList(); QList::const_iterator it_l; for (it_l = list.constBegin(); it_l != list.constEnd(); ++it_l) { if ((*it_l).isFinished()) continue; if ((*it_l).hasReferenceTo(acc.id())) return KMyMoneyUtils::AccountScheduleReference; } return KMyMoneyUtils::AccountCanClose; } void KMyMoneyApp::slotAccountClose() { MyMoneyAccount a; if (!d->m_selectedInvestment.id().isEmpty()) a = d->m_selectedInvestment; else if (!d->m_selectedAccount.id().isEmpty()) a = d->m_selectedAccount; if (a.id().isEmpty()) return; // need an account ID MyMoneyFileTransaction ft; try { a.setClosed(true); MyMoneyFile::instance()->modifyAccount(a); ft.commit(); if (KMyMoneyGlobalSettings::hideClosedAccounts()) { KMessageBox::information(this, QString("") + i18n("You have closed this account. It remains in the system because you have transactions which still refer to it, but it is not shown in the views. You can make it visible again by going to the View menu and selecting Show all accounts or by deselecting the Do not show closed accounts setting.") + QString(""), i18n("Information"), "CloseAccountInfo"); } } catch (const MyMoneyException &) { } } void KMyMoneyApp::slotAccountReopen() { MyMoneyAccount a; if (!d->m_selectedInvestment.id().isEmpty()) a = d->m_selectedInvestment; else if (!d->m_selectedAccount.id().isEmpty()) a = d->m_selectedAccount; if (a.id().isEmpty()) return; // need an account ID MyMoneyFile* file = MyMoneyFile::instance(); MyMoneyFileTransaction ft; try { while (a.isClosed()) { a.setClosed(false); file->modifyAccount(a); a = file->account(a.parentAccountId()); } ft.commit(); } catch (const MyMoneyException &) { } } void KMyMoneyApp::slotReparentAccount(const MyMoneyAccount& _src, const MyMoneyInstitution& _dst) { MyMoneyAccount src(_src); src.setInstitutionId(_dst.id()); MyMoneyFileTransaction ft; try { MyMoneyFile::instance()->modifyAccount(src); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::sorry(this, i18n("

%1 cannot be moved to institution %2. Reason: %3

", src.name(), _dst.name(), e.what())); } } void KMyMoneyApp::slotReparentAccount(const MyMoneyAccount& _src, const MyMoneyAccount& _dst) { MyMoneyAccount src(_src); MyMoneyAccount dst(_dst); MyMoneyFileTransaction ft; try { MyMoneyFile::instance()->reparentAccount(src, dst); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::sorry(this, i18n("

%1 cannot be moved to %2. Reason: %3

", src.name(), dst.name(), e.what())); } } void KMyMoneyApp::slotAccountTransactionReport() { // Generate a transaction report that contains transactions for only the // currently selected account. if (!d->m_selectedAccount.id().isEmpty()) { MyMoneyReport report( MyMoneyReport::eAccount, MyMoneyReport::eQCnumber | MyMoneyReport::eQCpayee | MyMoneyReport::eQCcategory, eMyMoney::TransactionFilter::Date::YearToDate, MyMoneyReport::eDetailAll, i18n("%1 YTD Account Transactions", d->m_selectedAccount.name()), i18n("Generated Report") ); report.setGroup(i18n("Transactions")); report.addAccount(d->m_selectedAccount.id()); d->m_myMoneyView->slotShowReport(report); } } void KMyMoneyApp::slotScheduleNew() { slotScheduleNew(MyMoneyTransaction()); } void KMyMoneyApp::slotScheduleNew(const MyMoneyTransaction& _t, eMyMoney::Schedule::Occurrence occurrence) { MyMoneySchedule schedule; schedule.setOccurrence(occurrence); // if the schedule is based on an existing transaction, // we take the post date and project it to the next // schedule in a month. if (_t != MyMoneyTransaction()) { MyMoneyTransaction t(_t); schedule.setTransaction(t); if (occurrence != eMyMoney::Schedule::Occurrence::Once) schedule.setNextDueDate(schedule.nextPayment(t.postDate())); } QPointer dlg = new KEditScheduleDlg(schedule, this); TransactionEditor* transactionEditor = dlg->startEdit(); if (transactionEditor) { KMyMoneyMVCCombo::setSubstringSearchForChildren(dlg, !KMyMoneySettings::stringMatchFromStart()); if (dlg->exec() == QDialog::Accepted && dlg != 0) { MyMoneyFileTransaction ft; try { schedule = dlg->schedule(); MyMoneyFile::instance()->addSchedule(schedule); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::error(this, i18n("Unable to add scheduled transaction: %1", e.what()), i18n("Add scheduled transaction")); } } } delete transactionEditor; delete dlg; } void KMyMoneyApp::slotScheduleEdit() { if (!d->m_selectedSchedule.id().isEmpty()) { try { MyMoneySchedule schedule = MyMoneyFile::instance()->schedule(d->m_selectedSchedule.id()); KEditScheduleDlg* sched_dlg = 0; KEditLoanWizard* loan_wiz = 0; switch (schedule.type()) { case eMyMoney::Schedule::Type::Bill: case eMyMoney::Schedule::Type::Deposit: case eMyMoney::Schedule::Type::Transfer: sched_dlg = new KEditScheduleDlg(schedule, this); d->m_transactionEditor = sched_dlg->startEdit(); if (d->m_transactionEditor) { KMyMoneyMVCCombo::setSubstringSearchForChildren(sched_dlg, !KMyMoneySettings::stringMatchFromStart()); if (sched_dlg->exec() == QDialog::Accepted) { MyMoneyFileTransaction ft; try { MyMoneySchedule sched = sched_dlg->schedule(); // Check whether the new Schedule Date // is at or before the lastPaymentDate // If it is, ask the user whether to clear the // lastPaymentDate const QDate& next = sched.nextDueDate(); const QDate& last = sched.lastPayment(); if (next.isValid() && last.isValid() && next <= last) { // Entered a date effectively no later // than previous payment. Date would be // updated automatically so we probably // want to clear it. Let's ask the user. if (KMessageBox::questionYesNo(this, QString("") + i18n("You have entered a scheduled transaction date of %1. Because the scheduled transaction was last paid on %2, KMyMoney will automatically adjust the scheduled transaction date to the next date unless the last payment date is reset. Do you want to reset the last payment date?", QLocale().toString(next, QLocale::ShortFormat), QLocale().toString(last, QLocale::ShortFormat)) + QString(""), i18n("Reset Last Payment Date"), KStandardGuiItem::yes(), KStandardGuiItem::no()) == KMessageBox::Yes) { sched.setLastPayment(QDate()); } } MyMoneyFile::instance()->modifySchedule(sched); // delete the editor before we emit the dataChanged() signal from the // engine. Calling this twice in a row does not hurt. deleteTransactionEditor(); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(this, i18n("Unable to modify scheduled transaction '%1'", d->m_selectedSchedule.name()), e.what()); } } deleteTransactionEditor(); } delete sched_dlg; break; case eMyMoney::Schedule::Type::LoanPayment: loan_wiz = new KEditLoanWizard(schedule.account(2)); connect(loan_wiz, SIGNAL(newCategory(MyMoneyAccount&)), this, SLOT(slotCategoryNew(MyMoneyAccount&))); connect(loan_wiz, SIGNAL(createPayee(QString,QString&)), this, SLOT(slotPayeeNew(QString,QString&))); if (loan_wiz->exec() == QDialog::Accepted) { MyMoneyFileTransaction ft; try { MyMoneyFile::instance()->modifySchedule(loan_wiz->schedule()); MyMoneyFile::instance()->modifyAccount(loan_wiz->account()); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(this, i18n("Unable to modify scheduled transaction '%1'", d->m_selectedSchedule.name()), e.what()); } } delete loan_wiz; break; case eMyMoney::Schedule::Type::Any: break; } } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(this, i18n("Unable to modify scheduled transaction '%1'", d->m_selectedSchedule.name()), e.what()); } } } void KMyMoneyApp::slotScheduleDelete() { if (!d->m_selectedSchedule.id().isEmpty()) { MyMoneyFileTransaction ft; try { MyMoneySchedule sched = MyMoneyFile::instance()->schedule(d->m_selectedSchedule.id()); QString msg = i18n("

Are you sure you want to delete the scheduled transaction %1?

", d->m_selectedSchedule.name()); if (sched.type() == eMyMoney::Schedule::Type::LoanPayment) { msg += QString(" "); msg += i18n("In case of loan payments it is currently not possible to recreate the scheduled transaction."); } if (KMessageBox::questionYesNo(this, msg) == KMessageBox::No) return; MyMoneyFile::instance()->removeSchedule(sched); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(this, i18n("Unable to remove scheduled transaction '%1'", d->m_selectedSchedule.name()), e.what()); } } } void KMyMoneyApp::slotScheduleDuplicate() { // since we may jump here via code, we have to make sure to react only // if the action is enabled if (kmymoney->actionCollection()->action(s_Actions[Action::ScheduleDuplicate])->isEnabled()) { MyMoneySchedule sch = d->m_selectedSchedule; sch.clearId(); sch.setLastPayment(QDate()); sch.setName(i18nc("Copy of scheduled transaction name", "Copy of %1", sch.name())); // make sure that we set a valid next due date if the original next due date is invalid if (!sch.nextDueDate().isValid()) sch.setNextDueDate(QDate::currentDate()); MyMoneyFileTransaction ft; try { MyMoneyFile::instance()->addSchedule(sch); ft.commit(); // select the new schedule in the view if (!d->m_selectedSchedule.id().isEmpty()) d->m_myMoneyView->slotScheduleSelected(sch.id()); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Unable to duplicate scheduled transaction: '%1'", d->m_selectedSchedule.name()), e.what()); } } } void KMyMoneyApp::slotScheduleSkip() { if (!d->m_selectedSchedule.id().isEmpty()) { try { MyMoneySchedule schedule = MyMoneyFile::instance()->schedule(d->m_selectedSchedule.id()); skipSchedule(schedule); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(this, i18n("Unknown scheduled transaction '%1'", d->m_selectedSchedule.name()), e.what()); } } } void KMyMoneyApp::skipSchedule(MyMoneySchedule& schedule) { if (!schedule.id().isEmpty()) { try { schedule = MyMoneyFile::instance()->schedule(schedule.id()); if (!schedule.isFinished()) { if (schedule.occurrence() != eMyMoney::Schedule::Occurrence::Once) { QDate next = schedule.nextDueDate(); if (!schedule.isFinished() && (KMessageBox::questionYesNo(this, QString("") + i18n("Do you really want to skip the %1 transaction scheduled for %2?", schedule.name(), QLocale().toString(next, QLocale::ShortFormat)) + QString(""))) == KMessageBox::Yes) { MyMoneyFileTransaction ft; schedule.setLastPayment(next); schedule.setNextDueDate(schedule.nextPayment(next)); MyMoneyFile::instance()->modifySchedule(schedule); ft.commit(); } } } } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(this, QString("") + i18n("Unable to skip scheduled transaction %1.", schedule.name()) + QString(""), e.what()); } } } void KMyMoneyApp::slotScheduleEnter() { if (!d->m_selectedSchedule.id().isEmpty()) { try { MyMoneySchedule schedule = MyMoneyFile::instance()->schedule(d->m_selectedSchedule.id()); enterSchedule(schedule); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(this, i18n("Unknown scheduled transaction '%1'", d->m_selectedSchedule.name()), e.what()); } } } -KMyMoneyUtils::EnterScheduleResultCodeE KMyMoneyApp::enterSchedule(MyMoneySchedule& schedule, bool autoEnter, bool extendedKeys) +eDialogs::ScheduleResultCode KMyMoneyApp::enterSchedule(MyMoneySchedule& schedule, bool autoEnter, bool extendedKeys) { - KMyMoneyUtils::EnterScheduleResultCodeE rc = KMyMoneyUtils::Cancel; + eDialogs::ScheduleResultCode rc = eDialogs::ScheduleResultCode::Cancel; if (!schedule.id().isEmpty()) { try { schedule = MyMoneyFile::instance()->schedule(schedule.id()); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(this, i18n("Unable to enter scheduled transaction '%1'", schedule.name()), e.what()); return rc; } QPointer dlg = new KEnterScheduleDlg(this, schedule); try { QDate origDueDate = schedule.nextDueDate(); dlg->showExtendedKeys(extendedKeys); d->m_transactionEditor = dlg->startEdit(); if (d->m_transactionEditor) { KMyMoneyMVCCombo::setSubstringSearchForChildren(dlg, !KMyMoneySettings::stringMatchFromStart()); MyMoneyTransaction torig, taccepted; d->m_transactionEditor->createTransaction(torig, dlg->transaction(), schedule.transaction().splits().isEmpty() ? MyMoneySplit() : schedule.transaction().splits().front(), true); // force actions to be available no matter what (will be updated according to the state during // slotTransactionsEnter or slotTransactionsCancel) kmymoney->actionCollection()->action(s_Actions[Action::TransactionCancel])->setEnabled(true); kmymoney->actionCollection()->action(s_Actions[Action::TransactionEnter])->setEnabled(true); KConfirmManualEnterDlg::Action action = KConfirmManualEnterDlg::ModifyOnce; if (!autoEnter || !schedule.isFixed()) { for (; dlg != 0;) { - rc = KMyMoneyUtils::Cancel; + rc = eDialogs::ScheduleResultCode::Cancel; if (dlg->exec() == QDialog::Accepted && dlg != 0) { rc = dlg->resultCode(); - if (rc == KMyMoneyUtils::Enter) { + if (rc == eDialogs::ScheduleResultCode::Enter) { d->m_transactionEditor->createTransaction(taccepted, torig, torig.splits().isEmpty() ? MyMoneySplit() : torig.splits().front(), true); // make sure to suppress comparison of some data: postDate torig.setPostDate(taccepted.postDate()); if (torig != taccepted) { QPointer cdlg = new KConfirmManualEnterDlg(schedule, this); cdlg->loadTransactions(torig, taccepted); if (cdlg->exec() == QDialog::Accepted) { action = cdlg->action(); delete cdlg; break; } delete cdlg; // the user has chosen 'cancel' during confirmation, // we go back to the editor continue; } - } else if (rc == KMyMoneyUtils::Skip) { + } else if (rc == eDialogs::ScheduleResultCode::Skip) { slotTransactionsCancel(); skipSchedule(schedule); } else { slotTransactionsCancel(); } } else { if (autoEnter) { if (KMessageBox::warningYesNo(this, i18n("Are you sure you wish to stop this scheduled transaction from being entered into the register?\n\nKMyMoney will prompt you again next time it starts unless you manually enter it later.")) == KMessageBox::No) { // the user has chosen 'No' for the above question, // we go back to the editor continue; } } slotTransactionsCancel(); } break; } } // if we still have the editor around here, the user did not cancel if ((d->m_transactionEditor != 0) && (dlg != 0)) { MyMoneyFileTransaction ft; try { MyMoneyTransaction t; // add the new transaction switch (action) { case KConfirmManualEnterDlg::UseOriginal: // setup widgets with original transaction data d->m_transactionEditor->setTransaction(dlg->transaction(), dlg->transaction().splits().isEmpty() ? MyMoneySplit() : dlg->transaction().splits().front()); // and create a transaction based on that data taccepted = MyMoneyTransaction(); d->m_transactionEditor->createTransaction(taccepted, dlg->transaction(), dlg->transaction().splits().isEmpty() ? MyMoneySplit() : dlg->transaction().splits().front(), true); break; case KConfirmManualEnterDlg::ModifyAlways: torig = taccepted; torig.setPostDate(origDueDate); schedule.setTransaction(torig); break; case KConfirmManualEnterDlg::ModifyOnce: break; } QString newId; connect(d->m_transactionEditor, SIGNAL(balanceWarning(QWidget*,MyMoneyAccount,QString)), d->m_balanceWarning, SLOT(slotShowMessage(QWidget*,MyMoneyAccount,QString))); if (d->m_transactionEditor->enterTransactions(newId, false)) { if (!newId.isEmpty()) { MyMoneyTransaction t = MyMoneyFile::instance()->transaction(newId); schedule.setLastPayment(t.postDate()); } // in case the next due date is invalid, the schedule is finished // we mark it as such by setting the next due date to one day past the end QDate nextDueDate = schedule.nextPayment(origDueDate); if (!nextDueDate.isValid()) { schedule.setNextDueDate(schedule.endDate().addDays(1)); } else { schedule.setNextDueDate(nextDueDate); } MyMoneyFile::instance()->modifySchedule(schedule); - rc = KMyMoneyUtils::Enter; + rc = eDialogs::ScheduleResultCode::Enter; // delete the editor before we emit the dataChanged() signal from the // engine. Calling this twice in a row does not hurt. deleteTransactionEditor(); ft.commit(); } } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(this, i18n("Unable to enter scheduled transaction '%1'", schedule.name()), e.what()); } deleteTransactionEditor(); } } } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(this, i18n("Unable to enter scheduled transaction '%1'", schedule.name()), e.what()); } delete dlg; } return rc; } -bool KMyMoneyApp::slotPayeeNew(const QString& newnameBase, QString& id) +void KMyMoneyApp::slotPayeeNew(const QString& newnameBase, QString& id) +{ + createPayeeNew(newnameBase, id); +} + +bool KMyMoneyApp::createPayeeNew(const QString& newnameBase, QString& id) { bool doit = true; if (newnameBase != i18n("New Payee")) { // Ask the user if that is what he intended to do? QString msg = QLatin1String("") + i18n("Do you want to add %1 as payer/receiver?", newnameBase) + QLatin1String(""); if (KMessageBox::questionYesNo(this, msg, i18n("New payee/receiver"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "NewPayee") == KMessageBox::No) { doit = false; // we should not keep the 'no' setting because that can confuse people like // I have seen in some usability tests. So we just delete it right away. KSharedConfigPtr kconfig = KSharedConfig::openConfig(); if (kconfig) { kconfig->group(QLatin1String("Notification Messages")).deleteEntry(QLatin1String("NewPayee")); } } } if (doit) { MyMoneyFileTransaction ft; try { QString newname(newnameBase); // adjust name until a unique name has been created int count = 0; for (;;) { try { MyMoneyFile::instance()->payeeByName(newname); newname = QString("%1 [%2]").arg(newnameBase).arg(++count); } catch (const MyMoneyException &) { break; } } MyMoneyPayee p; p.setName(newname); MyMoneyFile::instance()->addPayee(p); id = p.id(); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(this, i18n("Unable to add payee"), i18n("%1 thrown in %2:%3", e.what(), e.file(), e.line())); doit = false; } } return doit; } void KMyMoneyApp::slotPayeeNew() { QString id; slotPayeeNew(i18n("New Payee"), id); // the callbacks should have made sure, that the payees view has been // updated already. So we search for the id in the list of items // and select it. emit payeeCreated(id); } bool KMyMoneyApp::payeeInList(const QList& list, const QString& id) const { bool rc = false; QList::const_iterator it_p = list.begin(); while (it_p != list.end()) { if ((*it_p).id() == id) { rc = true; break; } ++it_p; } return rc; } void KMyMoneyApp::slotPayeeDelete() { if (d->m_selectedPayees.isEmpty()) return; // shouldn't happen // get confirmation from user QString prompt; if (d->m_selectedPayees.size() == 1) prompt = i18n("

Do you really want to remove the payee %1?

", d->m_selectedPayees.front().name()); else prompt = i18n("Do you really want to remove all selected payees?"); if (KMessageBox::questionYesNo(this, prompt, i18n("Remove Payee")) == KMessageBox::No) return; payeeReassign(KPayeeReassignDlg::TypeDelete); } void KMyMoneyApp::slotPayeeMerge() { if (d->m_selectedPayees.size() < 1) return; // shouldn't happen if (KMessageBox::questionYesNo(this, i18n("

Do you really want to merge the selected payees?"), i18n("Merge Payees")) == KMessageBox::No) return; if (payeeReassign(KPayeeReassignDlg::TypeMerge)) // clean selection since we just deleted the selected payees slotSelectPayees(QList()); } bool KMyMoneyApp::payeeReassign(int type) { if (!(type >= 0 && type < KPayeeReassignDlg::TypeCount)) return false; MyMoneyFile * file = MyMoneyFile::instance(); MyMoneyFileTransaction ft; try { // create a transaction filter that contains all payees selected for removal MyMoneyTransactionFilter f = MyMoneyTransactionFilter(); for (QList::const_iterator it = d->m_selectedPayees.constBegin(); it != d->m_selectedPayees.constEnd(); ++it) { f.addPayee((*it).id()); } // request a list of all transactions that still use the payees in question QList translist = file->transactionList(f); // qDebug() << "[KPayeesView::slotDeletePayee] " << translist.count() << " transaction still assigned to payees"; // now get a list of all schedules that make use of one of the payees QList all_schedules = file->scheduleList(); QList used_schedules; for (QList::ConstIterator it = all_schedules.constBegin(); it != all_schedules.constEnd(); ++it) { // loop over all splits in the transaction of the schedule for (QList::ConstIterator s_it = (*it).transaction().splits().constBegin(); s_it != (*it).transaction().splits().constEnd(); ++s_it) { // is the payee in the split to be deleted? if (payeeInList(d->m_selectedPayees, (*s_it).payeeId())) { used_schedules.push_back(*it); // remember this schedule break; } } } // qDebug() << "[KPayeesView::slotDeletePayee] " << used_schedules.count() << " schedules use one of the selected payees"; // and a list of all loan accounts that references one of the payees QList allAccounts; QList usedAccounts; file->accountList(allAccounts); foreach (const MyMoneyAccount &account, allAccounts) { if (account.isLoan()) { MyMoneyAccountLoan loanAccount(account); foreach (const MyMoneyPayee &payee, d->m_selectedPayees) { if (loanAccount.hasReferenceTo(payee.id())) { usedAccounts.append(account); } } } } MyMoneyPayee newPayee; bool addToMatchList = false; // if at least one payee is still referenced, we need to reassign its transactions first if (!translist.isEmpty() || !used_schedules.isEmpty() || !usedAccounts.isEmpty()) { // first create list with all non-selected payees QList remainingPayees; if (type == KPayeeReassignDlg::TypeMerge) { remainingPayees = d->m_selectedPayees; } else { remainingPayees = file->payeeList(); QList::iterator it_p; for (it_p = remainingPayees.begin(); it_p != remainingPayees.end();) { if (d->m_selectedPayees.contains(*it_p)) { it_p = remainingPayees.erase(it_p); } else { ++it_p; } } } // show error message if no payees remain if (remainingPayees.isEmpty()) { KMessageBox::sorry(this, i18n("At least one transaction/scheduled transaction or loan account is still referenced by a payee. " "Currently you have all payees selected. However, at least one payee must remain so " "that the transaction/scheduled transaction or loan account can be reassigned.")); return false; } // show transaction reassignment dialog KPayeeReassignDlg * dlg = new KPayeeReassignDlg(static_cast(type), this); KMyMoneyMVCCombo::setSubstringSearchForChildren(dlg, !KMyMoneySettings::stringMatchFromStart()); QString payee_id = dlg->show(remainingPayees); addToMatchList = dlg->addToMatchList(); delete dlg; // and kill the dialog if (payee_id.isEmpty()) return false; // the user aborted the dialog, so let's abort as well // try to get selected payee. If not possible and we are merging payees, // then we create a new one try { newPayee = file->payee(payee_id); } catch (const MyMoneyException &e) { if (type == KPayeeReassignDlg::TypeMerge) { // it's ok to use payee_id for both arguments since the first is const, // so it's garantee not to change its content - if (!slotPayeeNew(payee_id, payee_id)) + if (!createPayeeNew(payee_id, payee_id)) return false; // the user aborted the dialog, so let's abort as well newPayee = file->payee(payee_id); } else { return false; } } // TODO : check if we have a report that explicitively uses one of our payees // and issue an appropriate warning try { QList::iterator s_it; // now loop over all transactions and reassign payee for (QList::iterator it = translist.begin(); it != translist.end(); ++it) { // create a copy of the splits list in the transaction QList splits = (*it).splits(); // loop over all splits for (s_it = splits.begin(); s_it != splits.end(); ++s_it) { // if the split is assigned to one of the selected payees, we need to modify it if (payeeInList(d->m_selectedPayees, (*s_it).payeeId())) { (*s_it).setPayeeId(payee_id); // first modify payee in current split // then modify the split in our local copy of the transaction list (*it).modifySplit(*s_it); // this does not modify the list object 'splits'! } } // for - Splits file->modifyTransaction(*it); // modify the transaction in the MyMoney object } // for - Transactions // now loop over all schedules and reassign payees for (QList::iterator it = used_schedules.begin(); it != used_schedules.end(); ++it) { // create copy of transaction in current schedule MyMoneyTransaction trans = (*it).transaction(); // create copy of lists of splits QList splits = trans.splits(); for (s_it = splits.begin(); s_it != splits.end(); ++s_it) { if (payeeInList(d->m_selectedPayees, (*s_it).payeeId())) { (*s_it).setPayeeId(payee_id); trans.modifySplit(*s_it); // does not modify the list object 'splits'! } } // for - Splits // store transaction in current schedule (*it).setTransaction(trans); file->modifySchedule(*it); // modify the schedule in the MyMoney engine } // for - Schedules // reassign the payees in the loans that reference the deleted payees foreach (const MyMoneyAccount &account, usedAccounts) { MyMoneyAccountLoan loanAccount(account); loanAccount.setPayee(payee_id); file->modifyAccount(loanAccount); } } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Unable to reassign payee of transaction/split"), i18n("%1 thrown in %2:%3", e.what(), e.file(), e.line())); } } else { // if !translist.isEmpty() if (type == KPayeeReassignDlg::TypeMerge) { KMessageBox::sorry(this, i18n("Nothing to merge."), i18n("Merge Payees")); return false; } } bool ignorecase; QStringList payeeNames; MyMoneyPayee::payeeMatchType matchType = newPayee.matchData(ignorecase, payeeNames); QStringList deletedPayeeNames; // now loop over all selected payees and remove them for (QList::iterator it = d->m_selectedPayees.begin(); it != d->m_selectedPayees.end(); ++it) { if (newPayee.id() != (*it).id()) { if (addToMatchList) { deletedPayeeNames << (*it).name(); } file->removePayee(*it); } } // if we initially have no matching turned on, we just ignore the case (default) if (matchType == MyMoneyPayee::matchDisabled) ignorecase = true; // update the destination payee if this was requested by the user if (addToMatchList && deletedPayeeNames.count() > 0) { // add new names to the list // TODO: it would be cool to somehow shrink the list to make better use // of regular expressions at this point. For now, we leave this task // to the user himeself. QStringList::const_iterator it_n; for (it_n = deletedPayeeNames.constBegin(); it_n != deletedPayeeNames.constEnd(); ++it_n) { if (matchType == MyMoneyPayee::matchKey) { // make sure we really need it and it is not caught by an existing regexp QStringList::const_iterator it_k; for (it_k = payeeNames.constBegin(); it_k != payeeNames.constEnd(); ++it_k) { QRegExp exp(*it_k, ignorecase ? Qt::CaseInsensitive : Qt::CaseSensitive); if (exp.indexIn(*it_n) != -1) break; } if (it_k == payeeNames.constEnd()) payeeNames << QRegExp::escape(*it_n); } else if (payeeNames.contains(*it_n) == 0) payeeNames << QRegExp::escape(*it_n); } // and update the payee in the engine context // make sure to turn on matching for this payee in the right mode newPayee.setMatchData(MyMoneyPayee::matchKey, ignorecase, payeeNames); file->modifyPayee(newPayee); } ft.commit(); // If we just deleted the payees, they sure don't exist anymore slotSelectPayees(QList()); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Unable to remove payee(s)"), i18n("%1 thrown in %2:%3", e.what(), e.file(), e.line())); } return true; } void KMyMoneyApp::slotTagNew(const QString& newnameBase, QString& id) { bool doit = true; if (newnameBase != i18n("New Tag")) { // Ask the user if that is what he intended to do? QString msg = QString("") + i18n("Do you want to add %1 as tag?", newnameBase) + QString(""); if (KMessageBox::questionYesNo(this, msg, i18n("New tag"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "NewTag") == KMessageBox::No) { doit = false; // we should not keep the 'no' setting because that can confuse people like // I have seen in some usability tests. So we just delete it right away. KSharedConfigPtr kconfig = KSharedConfig::openConfig(); if (kconfig) { kconfig->group(QLatin1String("Notification Messages")).deleteEntry(QLatin1String("NewTag")); } } } if (doit) { MyMoneyFileTransaction ft; try { QString newname(newnameBase); // adjust name until a unique name has been created int count = 0; for (;;) { try { MyMoneyFile::instance()->tagByName(newname); newname = QString("%1 [%2]").arg(newnameBase).arg(++count); } catch (const MyMoneyException &) { break; } } MyMoneyTag ta; ta.setName(newname); MyMoneyFile::instance()->addTag(ta); id = ta.id(); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(this, i18n("Unable to add tag"), i18n("%1 thrown in %2:%3", e.what(), e.file(), e.line())); } } } void KMyMoneyApp::slotTagNew() { QString id; slotTagNew(i18n("New Tag"), id); // the callbacks should have made sure, that the tags view has been // updated already. So we search for the id in the list of items // and select it. emit tagCreated(id); } bool KMyMoneyApp::tagInList(const QList& list, const QString& id) const { bool rc = false; QList::const_iterator it_p = list.begin(); while (it_p != list.end()) { if ((*it_p).id() == id) { rc = true; break; } ++it_p; } return rc; } void KMyMoneyApp::slotTagDelete() { if (d->m_selectedTags.isEmpty()) return; // shouldn't happen MyMoneyFile * file = MyMoneyFile::instance(); // first create list with all non-selected tags QList remainingTags = file->tagList(); QList::iterator it_ta; for (it_ta = remainingTags.begin(); it_ta != remainingTags.end();) { if (d->m_selectedTags.contains(*it_ta)) { it_ta = remainingTags.erase(it_ta); } else { ++it_ta; } } // get confirmation from user QString prompt; if (d->m_selectedTags.size() == 1) prompt = i18n("

Do you really want to remove the tag %1?

", d->m_selectedTags.front().name()); else prompt = i18n("Do you really want to remove all selected tags?"); if (KMessageBox::questionYesNo(this, prompt, i18n("Remove Tag")) == KMessageBox::No) return; MyMoneyFileTransaction ft; try { // create a transaction filter that contains all tags selected for removal MyMoneyTransactionFilter f = MyMoneyTransactionFilter(); for (QList::const_iterator it = d->m_selectedTags.constBegin(); it != d->m_selectedTags.constEnd(); ++it) { f.addTag((*it).id()); } // request a list of all transactions that still use the tags in question QList translist = file->transactionList(f); // qDebug() << "[KTagsView::slotDeleteTag] " << translist.count() << " transaction still assigned to tags"; // now get a list of all schedules that make use of one of the tags QList all_schedules = file->scheduleList(); QList used_schedules; for (QList::ConstIterator it = all_schedules.constBegin(); it != all_schedules.constEnd(); ++it) { // loop over all splits in the transaction of the schedule for (QList::ConstIterator s_it = (*it).transaction().splits().constBegin(); s_it != (*it).transaction().splits().constEnd(); ++s_it) { for (int i = 0; i < (*s_it).tagIdList().size(); i++) { // is the tag in the split to be deleted? if (tagInList(d->m_selectedTags, (*s_it).tagIdList()[i])) { used_schedules.push_back(*it); // remember this schedule break; } } } } // qDebug() << "[KTagsView::slotDeleteTag] " << used_schedules.count() << " schedules use one of the selected tags"; MyMoneyTag newTag; // if at least one tag is still referenced, we need to reassign its transactions first if (!translist.isEmpty() || !used_schedules.isEmpty()) { // show error message if no tags remain //FIXME-ALEX Tags are optional so we can delete all of them and simply delete every tagId from every transaction if (remainingTags.isEmpty()) { KMessageBox::sorry(this, i18n("At least one transaction/scheduled transaction is still referenced by a tag. " "Currently you have all tags selected. However, at least one tag must remain so " "that the transaction/scheduled transaction can be reassigned.")); return; } // show transaction reassignment dialog KTagReassignDlg * dlg = new KTagReassignDlg(this); KMyMoneyMVCCombo::setSubstringSearchForChildren(dlg, !KMyMoneySettings::stringMatchFromStart()); QString tag_id = dlg->show(remainingTags); delete dlg; // and kill the dialog if (tag_id.isEmpty()) //FIXME-ALEX Let the user choose to not reassign a to-be deleted tag to another one. return; // the user aborted the dialog, so let's abort as well newTag = file->tag(tag_id); // TODO : check if we have a report that explicitively uses one of our tags // and issue an appropriate warning try { QList::iterator s_it; // now loop over all transactions and reassign tag for (QList::iterator it = translist.begin(); it != translist.end(); ++it) { // create a copy of the splits list in the transaction QList splits = (*it).splits(); // loop over all splits for (s_it = splits.begin(); s_it != splits.end(); ++s_it) { QList tagIdList = (*s_it).tagIdList(); for (int i = 0; i < tagIdList.size(); i++) { // if the split is assigned to one of the selected tags, we need to modify it if (tagInList(d->m_selectedTags, tagIdList[i])) { tagIdList.removeAt(i); if (tagIdList.indexOf(tag_id) == -1) tagIdList.append(tag_id); i = -1; // restart from the first element } } (*s_it).setTagIdList(tagIdList); // first modify tag list in current split // then modify the split in our local copy of the transaction list (*it).modifySplit(*s_it); // this does not modify the list object 'splits'! } // for - Splits file->modifyTransaction(*it); // modify the transaction in the MyMoney object } // for - Transactions // now loop over all schedules and reassign tags for (QList::iterator it = used_schedules.begin(); it != used_schedules.end(); ++it) { // create copy of transaction in current schedule MyMoneyTransaction trans = (*it).transaction(); // create copy of lists of splits QList splits = trans.splits(); for (s_it = splits.begin(); s_it != splits.end(); ++s_it) { QList tagIdList = (*s_it).tagIdList(); for (int i = 0; i < tagIdList.size(); i++) { if (tagInList(d->m_selectedTags, tagIdList[i])) { tagIdList.removeAt(i); if (tagIdList.indexOf(tag_id) == -1) tagIdList.append(tag_id); i = -1; // restart from the first element } } (*s_it).setTagIdList(tagIdList); trans.modifySplit(*s_it); // does not modify the list object 'splits'! } // for - Splits // store transaction in current schedule (*it).setTransaction(trans); file->modifySchedule(*it); // modify the schedule in the MyMoney engine } // for - Schedules } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Unable to reassign tag of transaction/split"), i18n("%1 thrown in %2:%3", e.what(), e.file(), e.line())); } } // if !translist.isEmpty() // now loop over all selected tags and remove them for (QList::iterator it = d->m_selectedTags.begin(); it != d->m_selectedTags.end(); ++it) { file->removeTag(*it); } ft.commit(); // If we just deleted the tags, they sure don't exist anymore slotSelectTags(QList()); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Unable to remove tag(s)"), i18n("%1 thrown in %2:%3", e.what(), e.file(), e.line())); } } void KMyMoneyApp::slotCurrencyNew() { QString sid = QInputDialog::getText(0, i18n("New currency"), i18n("Enter ISO 4217 code for the new currency")); if (!sid.isEmpty()) { QString id(sid); MyMoneySecurity currency(id, i18n("New currency")); MyMoneyFileTransaction ft; try { MyMoneyFile::instance()->addCurrency(currency); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::sorry(this, i18n("Cannot create new currency. %1", e.what()), i18n("New currency")); } emit currencyCreated(id); } } void KMyMoneyApp::slotCurrencyUpdate(const QString ¤cyId, const QString& currencyName, const QString& currencyTradingSymbol) { MyMoneyFile* file = MyMoneyFile::instance(); try { if (currencyName != d->m_selectedCurrency.name() || currencyTradingSymbol != d->m_selectedCurrency.tradingSymbol()) { MyMoneySecurity currency = file->currency(currencyId); currency.setName(currencyName); currency.setTradingSymbol(currencyTradingSymbol); MyMoneyFileTransaction ft; try { file->modifyCurrency(currency); d->m_selectedCurrency = currency; ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::sorry(this, i18n("Cannot update currency. %1", e.what()), i18n("Update currency")); } } } catch (const MyMoneyException &e) { KMessageBox::sorry(this, i18n("Cannot update currency. %1", e.what()), i18n("Update currency")); } } void KMyMoneyApp::slotCurrencyDelete() { if (!d->m_selectedCurrency.id().isEmpty()) { MyMoneyFileTransaction ft; try { MyMoneyFile::instance()->removeCurrency(d->m_selectedCurrency); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::sorry(this, i18n("Cannot delete currency %1. %2", d->m_selectedCurrency.name(), e.what()), i18n("Delete currency")); } } } void KMyMoneyApp::slotCurrencySetBase() { if (!d->m_selectedCurrency.id().isEmpty()) { if (d->m_selectedCurrency.id() != MyMoneyFile::instance()->baseCurrency().id()) { MyMoneyFileTransaction ft; try { MyMoneyFile::instance()->setBaseCurrency(d->m_selectedCurrency); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::sorry(this, i18n("Cannot set %1 as base currency: %2", d->m_selectedCurrency.name(), e.what()), i18n("Set base currency")); } } } } void KMyMoneyApp::slotBudgetNew() { QDate date = QDate::currentDate(); date.setDate(date.year(), KMyMoneyGlobalSettings::firstFiscalMonth(), KMyMoneyGlobalSettings::firstFiscalDay()); QString newname = i18n("Budget %1", date.year()); MyMoneyBudget budget; // make sure we have a unique name try { int i = 1; // Exception thrown when the name is not found while (1) { MyMoneyFile::instance()->budgetByName(newname); newname = i18n("Budget %1 %2", date.year(), i++); } } catch (const MyMoneyException &) { // all ok, the name is unique } MyMoneyFileTransaction ft; try { budget.setName(newname); budget.setBudgetStart(date); MyMoneyFile::instance()->addBudget(budget); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to add budget: %1, thrown in %2:%3", e.what(), e.file(), e.line())); } } void KMyMoneyApp::slotBudgetDelete() { if (d->m_selectedBudgets.isEmpty()) return; // shouldn't happen MyMoneyFile * file = MyMoneyFile::instance(); // get confirmation from user QString prompt; if (d->m_selectedBudgets.size() == 1) prompt = i18n("

Do you really want to remove the budget %1?

", d->m_selectedBudgets.front().name()); else prompt = i18n("Do you really want to remove all selected budgets?"); if (KMessageBox::questionYesNo(this, prompt, i18n("Remove Budget")) == KMessageBox::No) return; MyMoneyFileTransaction ft; try { // now loop over all selected budgets and remove them for (QList::iterator it = d->m_selectedBudgets.begin(); it != d->m_selectedBudgets.end(); ++it) { file->removeBudget(*it); } ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to remove budget: %1, thrown in %2:%3", e.what(), e.file(), e.line())); } } void KMyMoneyApp::slotBudgetCopy() { if (d->m_selectedBudgets.size() == 1) { MyMoneyFileTransaction ft; try { MyMoneyBudget budget = d->m_selectedBudgets.first(); budget.clearId(); budget.setName(i18n("Copy of %1", budget.name())); MyMoneyFile::instance()->addBudget(budget); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to add budget: %1, thrown in %2:%3", e.what(), e.file(), e.line())); } } } void KMyMoneyApp::slotBudgetChangeYear() { if (d->m_selectedBudgets.size() == 1) { QStringList years; int current = 0; bool haveCurrent = false; MyMoneyBudget budget = *(d->m_selectedBudgets.begin()); for (int i = (QDate::currentDate().year() - 3); i < (QDate::currentDate().year() + 5); ++i) { years << QString("%1").arg(i); if (i == budget.budgetStart().year()) { haveCurrent = true; } if (!haveCurrent) ++current; } if (!haveCurrent) current = 0; bool ok = false; QString yearString = QInputDialog::getItem(this, i18n("Select year"), i18n("Budget year"), years, current, false, &ok); if (ok) { int year = yearString.toInt(0, 0); QDate newYear = QDate(year, budget.budgetStart().month(), budget.budgetStart().day()); if (newYear != budget.budgetStart()) { MyMoneyFileTransaction ft; try { budget.setBudgetStart(newYear); MyMoneyFile::instance()->modifyBudget(budget); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to modify budget: %1, thrown in %2:%3", e.what(), e.file(), e.line())); } } } } } void KMyMoneyApp::slotBudgetForecast() { if (d->m_selectedBudgets.size() == 1) { MyMoneyFileTransaction ft; try { MyMoneyBudget budget = d->m_selectedBudgets.first(); bool calcBudget = budget.getaccounts().count() == 0; if (!calcBudget) { if (KMessageBox::warningContinueCancel(0, i18n("The current budget already contains data. Continuing will replace all current values of this budget."), i18nc("Warning message box", "Warning")) == KMessageBox::Continue) calcBudget = true; } if (calcBudget) { QDate historyStart; QDate historyEnd; QDate budgetStart; QDate budgetEnd; budgetStart = budget.budgetStart(); budgetEnd = budgetStart.addYears(1).addDays(-1); historyStart = budgetStart.addYears(-1); historyEnd = budgetEnd.addYears(-1); MyMoneyForecast forecast = KMyMoneyGlobalSettings::forecast(); forecast.createBudget(budget, historyStart, historyEnd, budgetStart, budgetEnd, true); MyMoneyFile::instance()->modifyBudget(budget); ft.commit(); } } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to modify budget: %1, thrown in %2:%3", e.what(), e.file(), e.line())); } } } void KMyMoneyApp::slotNewFeature() { } void KMyMoneyApp::slotTransactionsDelete() { // since we may jump here via code, we have to make sure to react only // if the action is enabled if (!kmymoney->actionCollection()->action(s_Actions[Action::TransactionDelete])->isEnabled()) return; if (d->m_selectedTransactions.isEmpty()) return; if (d->m_selectedTransactions.warnLevel() == 1) { if (KMessageBox::warningContinueCancel(0, i18n("At least one split of the selected transactions has been reconciled. " "Do you wish to delete the transactions anyway?"), i18n("Transaction already reconciled")) == KMessageBox::Cancel) return; } QString msg = i18np("Do you really want to delete the selected transaction?", "Do you really want to delete all %1 selected transactions?", d->m_selectedTransactions.count()); if (KMessageBox::questionYesNo(this, msg, i18n("Delete transaction")) == KMessageBox::Yes) { KMSTATUS(i18n("Deleting transactions")); doDeleteTransactions(); } } void KMyMoneyApp::slotTransactionDuplicate() { // since we may jump here via code, we have to make sure to react only // if the action is enabled if (kmymoney->actionCollection()->action(s_Actions[Action::TransactionDuplicate])->isEnabled()) { KMyMoneyRegister::SelectedTransactions list = d->m_selectedTransactions; KMyMoneyRegister::SelectedTransactions::iterator it_t; int i = 0; int cnt = d->m_selectedTransactions.count(); KMSTATUS(i18n("Duplicating transactions")); slotStatusProgressBar(0, cnt); MyMoneyFileTransaction ft; MyMoneyTransaction lt; try { for (it_t = list.begin(); it_t != list.end(); ++it_t) { MyMoneyTransaction t = (*it_t).transaction(); QList::iterator it_s; // wipe out any reconciliation information for (it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) { (*it_s).setReconcileFlag(eMyMoney::Split::State::NotReconciled); (*it_s).setReconcileDate(QDate()); (*it_s).setBankID(QString()); } // clear invalid data t.setEntryDate(QDate()); t.clearId(); // and set the post date to today t.setPostDate(QDate::currentDate()); MyMoneyFile::instance()->addTransaction(t); lt = t; slotStatusProgressBar(i++, 0); } ft.commit(); // select the new transaction in the ledger if (!d->m_selectedAccount.id().isEmpty()) d->m_myMoneyView->slotLedgerSelected(d->m_selectedAccount.id(), lt.id()); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to duplicate transaction(s): %1, thrown in %2:%3", e.what(), e.file(), e.line())); } // switch off the progress bar slotStatusProgressBar(-1, -1); } } void KMyMoneyApp::doDeleteTransactions() { KMyMoneyRegister::SelectedTransactions list = d->m_selectedTransactions; KMyMoneyRegister::SelectedTransactions::iterator it_t; int cnt = list.count(); int i = 0; slotStatusProgressBar(0, cnt); MyMoneyFileTransaction ft; MyMoneyFile* file = MyMoneyFile::instance(); try { it_t = list.begin(); while (it_t != list.end()) { // only remove those transactions that do not reference a closed account if (!file->referencesClosedAccount((*it_t).transaction())) { file->removeTransaction((*it_t).transaction()); // remove all those references in the list of selected transactions // that refer to the same transaction we just removed so that we // will not be caught by an exception later on (see bko #285310) KMyMoneyRegister::SelectedTransactions::iterator it_td = it_t; ++it_td; while (it_td != list.end()) { if ((*it_t).transaction().id() == (*it_td).transaction().id()) { it_td = list.erase(it_td); i++; // bump count of deleted transactions } else { ++it_td; } } } // need to ensure "nextCheckNumber" is still correct MyMoneyAccount acc = file->account((*it_t).split().accountId()); // the "lastNumberUsed" might have been the txn number deleted // so adjust it QString deletedNum = (*it_t).split().number(); // decrement deletedNum and set new "lastNumberUsed" QString num = KMyMoneyUtils::getAdjacentNumber(deletedNum, -1); acc.setValue("lastNumberUsed", num); file->modifyAccount(acc); list.erase(it_t); it_t = list.begin(); slotStatusProgressBar(i++, 0); } ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to delete transaction(s): %1, thrown in %2:%3", e.what(), e.file(), e.line())); } slotStatusProgressBar(-1, -1); } void KMyMoneyApp::slotTransactionsNew() { // since we jump here via code, we have to make sure to react only // if the action is enabled if (kmymoney->actionCollection()->action(s_Actions[Action::TransactionNew])->isEnabled()) { if (d->m_myMoneyView->createNewTransaction()) { d->m_transactionEditor = d->m_myMoneyView->startEdit(d->m_selectedTransactions); if (d->m_transactionEditor) { KMyMoneyMVCCombo::setSubstringSearchForChildren(d->m_myMoneyView, !KMyMoneySettings::stringMatchFromStart()); KMyMoneyPayeeCombo* payeeEdit = dynamic_cast(d->m_transactionEditor->haveWidget("payee")); if (payeeEdit && !d->m_lastPayeeEnteredId.isEmpty()) { // in case we entered a new transaction before and used a payee, // we reuse it here. Save the text to the edit widget, select it // so that hitting any character will start entering another payee. payeeEdit->setSelectedItem(d->m_lastPayeeEnteredId); payeeEdit->lineEdit()->selectAll(); } if (d->m_transactionEditor) { connect(d->m_transactionEditor, SIGNAL(statusProgress(int,int)), this, SLOT(slotStatusProgressBar(int,int))); connect(d->m_transactionEditor, SIGNAL(statusMsg(QString)), this, SLOT(slotStatusMsg(QString))); connect(d->m_transactionEditor, SIGNAL(scheduleTransaction(MyMoneyTransaction,eMyMoney::Schedule::Occurrence)), this, SLOT(slotScheduleNew(MyMoneyTransaction,eMyMoney::Schedule::Occurrence))); } slotUpdateActions(); } } } } void KMyMoneyApp::slotTransactionsEdit() { // qDebug("KMyMoneyApp::slotTransactionsEdit()"); // since we jump here via code, we have to make sure to react only // if the action is enabled if (kmymoney->actionCollection()->action(s_Actions[Action::TransactionEdit])->isEnabled()) { // as soon as we edit a transaction, we don't remember the last payee entered d->m_lastPayeeEnteredId.clear(); d->m_transactionEditor = d->m_myMoneyView->startEdit(d->m_selectedTransactions); KMyMoneyMVCCombo::setSubstringSearchForChildren(d->m_myMoneyView, !KMyMoneySettings::stringMatchFromStart()); slotUpdateActions(); } } void KMyMoneyApp::deleteTransactionEditor() { // make sure, we don't use the transaction editor pointer // anymore from now on TransactionEditor* p = d->m_transactionEditor; d->m_transactionEditor = 0; delete p; } void KMyMoneyApp::slotTransactionsEditSplits() { // since we jump here via code, we have to make sure to react only // if the action is enabled if (kmymoney->actionCollection()->action(s_Actions[Action::TransactionEditSplits])->isEnabled()) { // as soon as we edit a transaction, we don't remember the last payee entered d->m_lastPayeeEnteredId.clear(); d->m_transactionEditor = d->m_myMoneyView->startEdit(d->m_selectedTransactions); slotUpdateActions(); if (d->m_transactionEditor) { KMyMoneyMVCCombo::setSubstringSearchForChildren(d->m_myMoneyView, !KMyMoneySettings::stringMatchFromStart()); if (d->m_transactionEditor->slotEditSplits() == QDialog::Accepted) { MyMoneyFileTransaction ft; try { QString id; connect(d->m_transactionEditor, SIGNAL(balanceWarning(QWidget*,MyMoneyAccount,QString)), d->m_balanceWarning, SLOT(slotShowMessage(QWidget*,MyMoneyAccount,QString))); d->m_transactionEditor->enterTransactions(id); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to modify transaction: %1, thrown in %2:%3", e.what(), e.file(), e.line())); } } } deleteTransactionEditor(); slotUpdateActions(); } } void KMyMoneyApp::slotTransactionsCancel() { // since we jump here via code, we have to make sure to react only // if the action is enabled if (kmymoney->actionCollection()->action(s_Actions[Action::TransactionCancel])->isEnabled()) { // make sure, we block the enter function actionCollection()->action(s_Actions[Action::TransactionEnter])->setEnabled(false); // qDebug("KMyMoneyApp::slotTransactionsCancel"); deleteTransactionEditor(); slotUpdateActions(); } } void KMyMoneyApp::slotTransactionsEnter() { // since we jump here via code, we have to make sure to react only // if the action is enabled if (kmymoney->actionCollection()->action(s_Actions[Action::TransactionEnter])->isEnabled()) { // disable the action while we process it to make sure it's processed only once since // d->m_transactionEditor->enterTransactions(newId) will run QCoreApplication::processEvents // we could end up here twice which will cause a crash slotUpdateActions() will enable the action again kmymoney->actionCollection()->action(s_Actions[Action::TransactionEnter])->setEnabled(false); if (d->m_transactionEditor) { QString accountId = d->m_selectedAccount.id(); QString newId; connect(d->m_transactionEditor, SIGNAL(balanceWarning(QWidget*,MyMoneyAccount,QString)), d->m_balanceWarning, SLOT(slotShowMessage(QWidget*,MyMoneyAccount,QString))); if (d->m_transactionEditor->enterTransactions(newId)) { KMyMoneyPayeeCombo* payeeEdit = dynamic_cast(d->m_transactionEditor->haveWidget("payee")); if (payeeEdit && !newId.isEmpty()) { d->m_lastPayeeEnteredId = payeeEdit->selectedItem(); } deleteTransactionEditor(); } if (!newId.isEmpty()) { d->m_myMoneyView->slotLedgerSelected(accountId, newId); } } slotUpdateActions(); } } void KMyMoneyApp::slotTransactionsCancelOrEnter(bool& okToSelect) { static bool oneTime = false; if (!oneTime) { oneTime = true; QString dontShowAgain = "CancelOrEditTransaction"; // qDebug("KMyMoneyApp::slotCancelOrEndEdit"); if (d->m_transactionEditor) { if (KMyMoneyGlobalSettings::focusChangeIsEnter() && kmymoney->actionCollection()->action(s_Actions[Action::TransactionEnter])->isEnabled()) { slotTransactionsEnter(); if (d->m_transactionEditor) { // if at this stage the editor is still there that means that entering the transaction was cancelled // for example by pressing cancel on the exchange rate editor so we must stay in edit mode okToSelect = false; } } else { // okToSelect is preset to true if a cancel of the dialog is useful and false if it is not int rc; KGuiItem noGuiItem = KStandardGuiItem::save(); KGuiItem yesGuiItem = KStandardGuiItem::discard(); KGuiItem cancelGuiItem = KStandardGuiItem::cont(); // if the transaction can't be entered make sure that it can't be entered by pressing no either if (!kmymoney->actionCollection()->action(s_Actions[Action::TransactionEnter])->isEnabled()) { noGuiItem.setEnabled(false); noGuiItem.setToolTip(kmymoney->actionCollection()->action(s_Actions[Action::TransactionEnter])->toolTip()); } if (okToSelect == true) { rc = KMessageBox::warningYesNoCancel(0, i18n("

Please select what you want to do: discard the changes, save the changes or continue to edit the transaction.

You can also set an option to save the transaction automatically when e.g. selecting another transaction.

"), i18n("End transaction edit"), yesGuiItem, noGuiItem, cancelGuiItem, dontShowAgain); } else { rc = KMessageBox::warningYesNo(0, i18n("

Please select what you want to do: discard the changes, save the changes or continue to edit the transaction.

You can also set an option to save the transaction automatically when e.g. selecting another transaction.

"), i18n("End transaction edit"), yesGuiItem, noGuiItem, dontShowAgain); } switch (rc) { case KMessageBox::Yes: slotTransactionsCancel(); break; case KMessageBox::No: slotTransactionsEnter(); // make sure that we'll see this message the next time no matter // if the user has chosen the 'Don't show again' checkbox KMessageBox::enableMessage(dontShowAgain); if (d->m_transactionEditor) { // if at this stage the editor is still there that means that entering the transaction was cancelled // for example by pressing cancel on the exchange rate editor so we must stay in edit mode okToSelect = false; } break; case KMessageBox::Cancel: // make sure that we'll see this message the next time no matter // if the user has chosen the 'Don't show again' checkbox KMessageBox::enableMessage(dontShowAgain); okToSelect = false; break; } } } oneTime = false; } } void KMyMoneyApp::slotToggleReconciliationFlag() { markTransaction(eMyMoney::Split::State::Unknown); } void KMyMoneyApp::slotMarkTransactionCleared() { markTransaction(eMyMoney::Split::State::Cleared); } void KMyMoneyApp::slotMarkTransactionReconciled() { markTransaction(eMyMoney::Split::State::Reconciled); } void KMyMoneyApp::slotMarkTransactionNotReconciled() { markTransaction(eMyMoney::Split::State::NotReconciled); } void KMyMoneyApp::markTransaction(eMyMoney::Split::State flag) { KMyMoneyRegister::SelectedTransactions list = d->m_selectedTransactions; KMyMoneyRegister::SelectedTransactions::const_iterator it_t; int cnt = list.count(); int i = 0; slotStatusProgressBar(0, cnt); MyMoneyFileTransaction ft; try { for (it_t = list.constBegin(); it_t != list.constEnd(); ++it_t) { // turn on signals before we modify the last entry in the list cnt--; MyMoneyFile::instance()->blockSignals(cnt != 0); // get a fresh copy MyMoneyTransaction t = MyMoneyFile::instance()->transaction((*it_t).transaction().id()); MyMoneySplit sp = t.splitById((*it_t).split().id()); if (sp.reconcileFlag() != flag) { if (flag == eMyMoney::Split::State::Unknown) { if (d->m_reconciliationAccount.id().isEmpty()) { // in normal mode we cycle through all states switch (sp.reconcileFlag()) { case eMyMoney::Split::State::NotReconciled: sp.setReconcileFlag(eMyMoney::Split::State::Cleared); break; case eMyMoney::Split::State::Cleared: sp.setReconcileFlag(eMyMoney::Split::State::Reconciled); break; case eMyMoney::Split::State::Reconciled: sp.setReconcileFlag(eMyMoney::Split::State::NotReconciled); break; default: break; } } else { // in reconciliation mode we skip the reconciled state switch (sp.reconcileFlag()) { case eMyMoney::Split::State::NotReconciled: sp.setReconcileFlag(eMyMoney::Split::State::Cleared); break; case eMyMoney::Split::State::Cleared: sp.setReconcileFlag(eMyMoney::Split::State::NotReconciled); break; default: break; } } } else { sp.setReconcileFlag(flag); } t.modifySplit(sp); MyMoneyFile::instance()->modifyTransaction(t); } slotStatusProgressBar(i++, 0); } slotStatusProgressBar(-1, -1); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to modify transaction: %1, thrown in %2:%3", e.what(), e.file(), e.line())); } } void KMyMoneyApp::slotTransactionsAccept() { KMyMoneyRegister::SelectedTransactions list = d->m_selectedTransactions; KMyMoneyRegister::SelectedTransactions::const_iterator it_t; int cnt = list.count(); int i = 0; slotStatusProgressBar(0, cnt); MyMoneyFileTransaction ft; try { for (it_t = list.constBegin(); it_t != list.constEnd(); ++it_t) { // reload transaction in case it got changed during the course of this loop MyMoneyTransaction t = MyMoneyFile::instance()->transaction((*it_t).transaction().id()); if (t.isImported()) { t.setImported(false); if (!d->m_selectedAccount.id().isEmpty()) { QList list = t.splits(); QList::const_iterator it_s; for (it_s = list.constBegin(); it_s != list.constEnd(); ++it_s) { if ((*it_s).accountId() == d->m_selectedAccount.id()) { if ((*it_s).reconcileFlag() == eMyMoney::Split::State::NotReconciled) { MyMoneySplit s = (*it_s); s.setReconcileFlag(eMyMoney::Split::State::Cleared); t.modifySplit(s); } } } } MyMoneyFile::instance()->modifyTransaction(t); } if ((*it_t).split().isMatched()) { // reload split in case it got changed during the course of this loop MyMoneySplit s = t.splitById((*it_t).split().id()); TransactionMatcher matcher(d->m_selectedAccount); matcher.accept(t, s); } slotStatusProgressBar(i++, 0); } slotStatusProgressBar(-1, -1); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Error"), i18n("Unable to accept transaction: %1, thrown in %2:%3", e.what(), e.file(), e.line())); } } void KMyMoneyApp::slotTransactionGotoAccount() { if (!d->m_accountGoto.isEmpty()) { try { QString transactionId; if (d->m_selectedTransactions.count() == 1) { transactionId = d->m_selectedTransactions[0].transaction().id(); } // make sure to pass a copy, as d->myMoneyView->slotLedgerSelected() overrides // d->m_accountGoto while calling slotUpdateActions() QString accountId = d->m_accountGoto; d->m_myMoneyView->slotLedgerSelected(accountId, transactionId); } catch (const MyMoneyException &) { } } } void KMyMoneyApp::slotTransactionGotoPayee() { if (!d->m_payeeGoto.isEmpty()) { try { QString transactionId; if (d->m_selectedTransactions.count() == 1) { transactionId = d->m_selectedTransactions[0].transaction().id(); } // make sure to pass copies, as d->myMoneyView->slotPayeeSelected() overrides // d->m_payeeGoto and d->m_selectedAccount while calling slotUpdateActions() QString payeeId = d->m_payeeGoto; QString accountId = d->m_selectedAccount.id(); d->m_myMoneyView->slotPayeeSelected(payeeId, accountId, transactionId); } catch (const MyMoneyException &) { } } } void KMyMoneyApp::slotTransactionCreateSchedule() { if (d->m_selectedTransactions.count() == 1) { // make sure to have the current selected split as first split in the schedule MyMoneyTransaction t = d->m_selectedTransactions[0].transaction(); MyMoneySplit s = d->m_selectedTransactions[0].split(); QString splitId = s.id(); s.clearId(); s.setReconcileFlag(eMyMoney::Split::State::NotReconciled); s.setReconcileDate(QDate()); t.removeSplits(); t.addSplit(s); const QList& splits = d->m_selectedTransactions[0].transaction().splits(); QList::const_iterator it_s; for (it_s = splits.begin(); it_s != splits.end(); ++it_s) { if ((*it_s).id() != splitId) { MyMoneySplit s0 = (*it_s); s0.clearId(); s0.setReconcileFlag(eMyMoney::Split::State::NotReconciled); s0.setReconcileDate(QDate()); t.addSplit(s0); } } slotScheduleNew(t); } } void KMyMoneyApp::slotTransactionAssignNumber() { if (d->m_transactionEditor) d->m_transactionEditor->assignNextNumber(); } void KMyMoneyApp::slotTransactionCombine() { qDebug("slotTransactionCombine() not implemented yet"); } void KMyMoneyApp::slotTransactionCopySplits() { MyMoneyFile* file = MyMoneyFile::instance(); if (d->m_selectedTransactions.count() >= 2) { int singleSplitTransactions = 0; int multipleSplitTransactions = 0; KMyMoneyRegister::SelectedTransaction selectedSourceTransaction; foreach (const KMyMoneyRegister::SelectedTransaction& st, d->m_selectedTransactions) { switch (st.transaction().splitCount()) { case 0: break; case 1: singleSplitTransactions++; break; default: selectedSourceTransaction = st; multipleSplitTransactions++; break; } } if (singleSplitTransactions > 0 && multipleSplitTransactions == 1) { MyMoneyFileTransaction ft; try { const MyMoneyTransaction& sourceTransaction = selectedSourceTransaction.transaction(); const MyMoneySplit& sourceSplit = selectedSourceTransaction.split(); foreach (const KMyMoneyRegister::SelectedTransaction& st, d->m_selectedTransactions) { MyMoneyTransaction t = st.transaction(); // don't process the source transaction if (sourceTransaction.id() == t.id()) { continue; } const MyMoneySplit& baseSplit = st.split(); if (t.splitCount() == 1) { foreach (const MyMoneySplit& split, sourceTransaction.splits()) { // Don't copy the source split, as we already have that // as part of the destination transaction if (split.id() == sourceSplit.id()) { continue; } MyMoneySplit sp(split); // clear the ID and reconciliation state sp.clearId(); sp.setReconcileFlag(eMyMoney::Split::State::NotReconciled); sp.setReconcileDate(QDate()); // in case it is a simple transaction consisting of two splits, // we can adjust the share and value part of the second split we // just created. We need to keep a possible price in mind in case // of different currencies if (sourceTransaction.splitCount() == 2) { sp.setValue(-baseSplit.value()); sp.setShares(-(baseSplit.shares() * baseSplit.price())); } t.addSplit(sp); } file->modifyTransaction(t); } } ft.commit(); } catch (const MyMoneyException &) { qDebug() << "transactionCopySplits() failed"; } } } } void KMyMoneyApp::slotMoveToAccount(const QString& id) { // close the menu, if it is still open QWidget* w = factory()->container("transaction_context_menu", this); if (w && w->isVisible()) { w->close(); } if (!d->m_selectedTransactions.isEmpty()) { MyMoneyFileTransaction ft; try { KMyMoneyRegister::SelectedTransactions::const_iterator it_t; for (it_t = d->m_selectedTransactions.constBegin(); it_t != d->m_selectedTransactions.constEnd(); ++it_t) { if (d->m_selectedAccount.accountType() == eMyMoney::Account::Investment) { d->moveInvestmentTransaction(d->m_selectedAccount.id(), id, (*it_t).transaction()); } else { QList::const_iterator it_s; bool changed = false; MyMoneyTransaction t = (*it_t).transaction(); for (it_s = (*it_t).transaction().splits().constBegin(); it_s != (*it_t).transaction().splits().constEnd(); ++it_s) { if ((*it_s).accountId() == d->m_selectedAccount.id()) { MyMoneySplit s = (*it_s); s.setAccountId(id); t.modifySplit(s); changed = true; } } if (changed) { MyMoneyFile::instance()->modifyTransaction(t); } } } ft.commit(); } catch (const MyMoneyException &) { } } } // move a stock transaction from one investment account to another void KMyMoneyApp::Private::moveInvestmentTransaction(const QString& /*fromId*/, const QString& toId, const MyMoneyTransaction& tx) { MyMoneyAccount toInvAcc = MyMoneyFile::instance()->account(toId); MyMoneyTransaction t(tx); // first determine which stock we are dealing with. // fortunately, investment transactions have only one stock involved QString stockAccountId; QString stockSecurityId; MyMoneySplit s; for (QList::const_iterator it_s = t.splits().constBegin(); it_s != t.splits().constEnd(); ++it_s) { stockAccountId = (*it_s).accountId(); stockSecurityId = MyMoneyFile::instance()->account(stockAccountId).currencyId(); if (!MyMoneyFile::instance()->security(stockSecurityId).isCurrency()) { s = *it_s; break; } } // Now check the target investment account to see if it // contains a stock with this id QString newStockAccountId; QStringList accountList = toInvAcc.accountList(); for (QStringList::const_iterator it_a = accountList.constBegin(); it_a != accountList.constEnd(); ++it_a) { if (MyMoneyFile::instance()->account((*it_a)).currencyId() == stockSecurityId) { newStockAccountId = (*it_a); break; } } // if it doesn't exist, we need to add it as a copy of the old one // no 'copyAccount()' function?? if (newStockAccountId.isEmpty()) { MyMoneyAccount stockAccount = MyMoneyFile::instance()->account(stockAccountId); MyMoneyAccount newStock; newStock.setName(stockAccount.name()); newStock.setNumber(stockAccount.number()); newStock.setDescription(stockAccount.description()); newStock.setInstitutionId(stockAccount.institutionId()); newStock.setOpeningDate(stockAccount.openingDate()); newStock.setAccountType(stockAccount.accountType()); newStock.setCurrencyId(stockAccount.currencyId()); newStock.setClosed(stockAccount.isClosed()); MyMoneyFile::instance()->addAccount(newStock, toInvAcc); newStockAccountId = newStock.id(); } // now update the split and the transaction s.setAccountId(newStockAccountId); t.modifySplit(s); MyMoneyFile::instance()->modifyTransaction(t); } void KMyMoneyApp::slotUpdateMoveToAccountMenu() { createTransactionMoveMenu(); // in case we were not able to create the selector, we // better get out of here. Anything else would cause // a crash later on (accountSet.load) if (!d->m_moveToAccountSelector) return; if (!d->m_selectedAccount.id().isEmpty()) { AccountSet accountSet; if (d->m_selectedAccount.accountType() == eMyMoney::Account::Investment) { accountSet.addAccountType(eMyMoney::Account::Investment); } else if (d->m_selectedAccount.isAssetLiability()) { accountSet.addAccountType(eMyMoney::Account::Checkings); accountSet.addAccountType(eMyMoney::Account::Savings); accountSet.addAccountType(eMyMoney::Account::Cash); accountSet.addAccountType(eMyMoney::Account::AssetLoan); accountSet.addAccountType(eMyMoney::Account::CertificateDep); accountSet.addAccountType(eMyMoney::Account::MoneyMarket); accountSet.addAccountType(eMyMoney::Account::Asset); accountSet.addAccountType(eMyMoney::Account::Currency); accountSet.addAccountType(eMyMoney::Account::CreditCard); accountSet.addAccountType(eMyMoney::Account::Loan); accountSet.addAccountType(eMyMoney::Account::Liability); } else if (d->m_selectedAccount.isIncomeExpense()) { accountSet.addAccountType(eMyMoney::Account::Income); accountSet.addAccountType(eMyMoney::Account::Expense); } accountSet.load(d->m_moveToAccountSelector); // remove those accounts that we currently reference KMyMoneyRegister::SelectedTransactions::const_iterator it_t; for (it_t = d->m_selectedTransactions.constBegin(); it_t != d->m_selectedTransactions.constEnd(); ++it_t) { QList::const_iterator it_s; for (it_s = (*it_t).transaction().splits().constBegin(); it_s != (*it_t).transaction().splits().constEnd(); ++it_s) { d->m_moveToAccountSelector->removeItem((*it_s).accountId()); } } // remove those accounts from the list that are denominated // in a different currency QStringList list = d->m_moveToAccountSelector->accountList(); QList::const_iterator it_a; for (it_a = list.constBegin(); it_a != list.constEnd(); ++it_a) { MyMoneyAccount acc = MyMoneyFile::instance()->account(*it_a); if (acc.currencyId() != d->m_selectedAccount.currencyId()) d->m_moveToAccountSelector->removeItem((*it_a)); } } } void KMyMoneyApp::slotTransactionMatch() { // if the menu action is retrieved it can contain an '&' character for the accelerator causing the comparison to fail if not removed QString transactionActionText = actionCollection()->action(s_Actions[Action::TransactionMatch])->text(); transactionActionText.remove('&'); if (transactionActionText == i18nc("Button text for match transaction", "Match")) transactionMatch(); else transactionUnmatch(); } void KMyMoneyApp::transactionUnmatch() { KMyMoneyRegister::SelectedTransactions::const_iterator it; MyMoneyFileTransaction ft; try { for (it = d->m_selectedTransactions.constBegin(); it != d->m_selectedTransactions.constEnd(); ++it) { if ((*it).split().isMatched()) { TransactionMatcher matcher(d->m_selectedAccount); matcher.unmatch((*it).transaction(), (*it).split()); } } ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Unable to unmatch the selected transactions"), e.what()); } } void KMyMoneyApp::transactionMatch() { if (d->m_selectedTransactions.count() != 2) return; MyMoneyTransaction startMatchTransaction; MyMoneyTransaction endMatchTransaction; MyMoneySplit startSplit; MyMoneySplit endSplit; KMyMoneyRegister::SelectedTransactions::const_iterator it; KMyMoneyRegister::SelectedTransactions toBeDeleted; for (it = d->m_selectedTransactions.constBegin(); it != d->m_selectedTransactions.constEnd(); ++it) { if ((*it).transaction().isImported()) { if (endMatchTransaction.id().isEmpty()) { endMatchTransaction = (*it).transaction(); endSplit = (*it).split(); toBeDeleted << *it; } else { //This is a second imported transaction, we still want to merge startMatchTransaction = (*it).transaction(); startSplit = (*it).split(); } } else if (!(*it).split().isMatched()) { if (startMatchTransaction.id().isEmpty()) { startMatchTransaction = (*it).transaction(); startSplit = (*it).split(); } else { endMatchTransaction = (*it).transaction(); endSplit = (*it).split(); toBeDeleted << *it; } } } #if 0 KMergeTransactionsDlg dlg(d->m_selectedAccount); dlg.addTransaction(startMatchTransaction); dlg.addTransaction(endMatchTransaction); if (dlg.exec() == QDialog::Accepted) #endif { MyMoneyFileTransaction ft; try { if (startMatchTransaction.id().isEmpty()) throw MYMONEYEXCEPTION(i18n("No manually entered transaction selected for matching")); if (endMatchTransaction.id().isEmpty()) throw MYMONEYEXCEPTION(i18n("No imported transaction selected for matching")); TransactionMatcher matcher(d->m_selectedAccount); matcher.match(startMatchTransaction, startSplit, endMatchTransaction, endSplit, true); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Unable to match the selected transactions"), e.what()); } } } void KMyMoneyApp::showContextMenu(const QString& containerName) { QWidget* w = factory()->container(containerName, this); QMenu *menu = dynamic_cast(w); if (menu) menu->exec(QCursor::pos()); else qDebug("menu '%s' not found: w = %p, menu = %p", qPrintable(containerName), w, menu); } void KMyMoneyApp::slotShowTransactionContextMenu() { if (d->m_selectedTransactions.isEmpty() && d->m_selectedSchedule != MyMoneySchedule()) { showContextMenu("schedule_context_menu"); } else { showContextMenu("transaction_context_menu"); } } void KMyMoneyApp::slotShowInvestmentContextMenu() { showContextMenu("investment_context_menu"); } void KMyMoneyApp::slotShowScheduleContextMenu() { showContextMenu("schedule_context_menu"); } void KMyMoneyApp::slotShowAccountContextMenu(const MyMoneyObject& obj) { // qDebug("KMyMoneyApp::slotShowAccountContextMenu"); if (typeid(obj) != typeid(MyMoneyAccount)) return; const MyMoneyAccount& acc = dynamic_cast(obj); // if the selected account is actually a stock account, we // call the right slot instead if (acc.isInvest()) { showContextMenu("investment_context_menu"); } else if (acc.isIncomeExpense()) { showContextMenu("category_context_menu"); } else { showContextMenu("account_context_menu"); } } void KMyMoneyApp::slotShowInstitutionContextMenu(const MyMoneyObject& obj) { if (typeid(obj) != typeid(MyMoneyInstitution)) return; showContextMenu("institution_context_menu"); } void KMyMoneyApp::slotShowPayeeContextMenu() { showContextMenu("payee_context_menu"); } void KMyMoneyApp::slotShowTagContextMenu() { showContextMenu("tag_context_menu"); } void KMyMoneyApp::slotShowBudgetContextMenu() { showContextMenu("budget_context_menu"); } void KMyMoneyApp::slotShowCurrencyContextMenu() { showContextMenu("currency_context_menu"); } void KMyMoneyApp::slotShowPriceContextMenu() { showContextMenu("price_context_menu"); } void KMyMoneyApp::slotShowOnlineJobContextMenu() { showContextMenu("onlinejob_context_menu"); } void KMyMoneyApp::slotPrintView() { d->m_myMoneyView->slotPrintView(); } void KMyMoneyApp::updateCaption(bool skipActions) { QString caption; caption = d->m_fileName.fileName(); if (caption.isEmpty() && d->m_myMoneyView && d->m_myMoneyView->fileOpen()) caption = i18n("Untitled"); // MyMoneyFile::instance()->dirty() throws an exception, if // there's no storage object available. In this case, we // assume that the storage object is not changed. Actually, // this can only happen if we are newly created early on. bool modified; try { modified = MyMoneyFile::instance()->dirty(); } catch (const MyMoneyException &) { modified = false; skipActions = true; } #ifdef KMM_DEBUG caption += QString(" (%1 x %2)").arg(width()).arg(height()); #endif setCaption(caption, modified); if (!skipActions) { d->m_myMoneyView->enableViewsIfFileOpen(); slotUpdateActions(); } } void KMyMoneyApp::slotUpdateActions() { MyMoneyFile* file = MyMoneyFile::instance(); const bool fileOpen = d->m_myMoneyView->fileOpen(); const bool modified = file->dirty(); const bool importRunning = (d->m_smtReader != 0); QWidget* w; KActionCollection *aC = actionCollection(); // ************* // Disabling actions to be disabled at this point // ************* { static const QVector disabledActions { Action::AccountStartReconciliation, Action::AccountFinishReconciliation, Action::AccountPostponeReconciliation, Action::AccountEdit, Action::AccountDelete, Action::AccountOpen, Action::AccountClose, Action::AccountReopen, Action::AccountTransactionReport, Action::AccountOnlineMap, Action::AccountOnlineUnmap, Action::AccountUpdate, Action::AccountUpdateAll, Action::AccountBalanceChart, Action::CategoryEdit, Action::CategoryDelete, Action::InstitutionEdit, Action::InstitutionDelete, Action::InvestmentEdit, Action::InvestmentNew, Action::InvestmentDelete, Action::InvestmentOnlinePrice, Action::InvestmentManualPrice, Action::ScheduleEdit, Action::ScheduleDelete, Action::ScheduleEnter, Action::ScheduleSkip, Action::PayeeDelete, Action::PayeeRename, Action::PayeeMerge, Action::TagDelete, Action::TagRename, Action::BudgetDelete, Action::BudgetRename, Action::BudgetChangeYear, Action::BudgetNew, Action::BudgetCopy, Action::BudgetForecast, Action::TransactionEdit, Action::TransactionEditSplits, Action::TransactionEnter, Action::TransactionCancel, Action::TransactionDelete, Action::TransactionMatch, Action::TransactionAccept, Action::TransactionDuplicate, Action::TransactionToggleReconciled, Action::TransactionToggleCleared, Action::TransactionGoToAccount, Action::TransactionGoToPayee, Action::TransactionAssignNumber, Action::TransactionCreateSchedule, Action::TransactionCombine, Action::TransactionSelectAll, Action::TransactionCopySplits, Action::ScheduleEdit, Action::ScheduleDelete, Action::ScheduleDuplicate, Action::ScheduleEnter, Action::ScheduleSkip, Action::CurrencyRename, Action::CurrencyDelete, Action::CurrencySetBase, Action::PriceEdit, Action::PriceDelete, Action::PriceUpdate }; foreach (const auto a, disabledActions) aC->action(s_Actions.value(a))->setEnabled(false); } // ************* // Disabling actions based on conditions // ************* { QString tooltip = i18n("Create a new transaction"); const QVector> actionStates { {qMakePair(Action::FileOpenDatabase, true)}, {qMakePair(Action::FileSaveAsDatabase, fileOpen)}, {qMakePair(Action::FilePersonalData, fileOpen)}, {qMakePair(Action::FileBackup, (fileOpen && !d->m_myMoneyView->isDatabase()))}, {qMakePair(Action::FileInformation, fileOpen)}, {qMakePair(Action::FileImportGNC, !importRunning)}, {qMakePair(Action::FileImportTemplate, fileOpen && !importRunning)}, {qMakePair(Action::FileExportTemplate, fileOpen && !importRunning)}, #ifdef KMM_DEBUG {qMakePair(Action::FileDump, fileOpen)}, #endif {qMakePair(Action::EditFindTransaction, fileOpen)}, {qMakePair(Action::ToolCurrencies, fileOpen)}, {qMakePair(Action::ToolPrices, fileOpen)}, {qMakePair(Action::ToolUpdatePrices, fileOpen)}, {qMakePair(Action::ToolConsistency, fileOpen)}, {qMakePair(Action::AccountNew, fileOpen)}, {qMakePair(Action::AccountCreditTransfer, onlineJobAdministration::instance()->canSendCreditTransfer())}, {qMakePair(Action::CategoryDelete, fileOpen)}, {qMakePair(Action::InstitutionNew, fileOpen)}, {qMakePair(Action::TransactionNew, (fileOpen && d->m_myMoneyView->canCreateTransactions(KMyMoneyRegister::SelectedTransactions(), tooltip)))}, {qMakePair(Action::ScheduleNew, fileOpen)}, {qMakePair(Action::CurrencyNew, fileOpen)}, {qMakePair(Action::PriceNew, fileOpen)}, }; foreach (const auto a, actionStates) aC->action(s_Actions.value(a.first))->setEnabled(a.second); } // ************* // Disabling standard actions based on conditions // ************* aC->action(QString::fromLatin1(KStandardAction::name(KStandardAction::Save)))->setEnabled(modified && !d->m_myMoneyView->isDatabase()); aC->action(QString::fromLatin1(KStandardAction::name(KStandardAction::SaveAs)))->setEnabled(fileOpen); aC->action(QString::fromLatin1(KStandardAction::name(KStandardAction::Close)))->setEnabled(fileOpen); aC->action(QString::fromLatin1(KStandardAction::name(KStandardAction::Print)))->setEnabled(fileOpen && d->m_myMoneyView->canPrint()); aC->action(s_Actions[Action::TransactionMatch])->setText(i18nc("Button text for match transaction", "Match")); aC->action(s_Actions[Action::TransactionNew])->setToolTip(i18n("Create a new transaction")); w = factory()->container(s_Actions[Action::TransactionMoveMenu], this); if (w) w->setEnabled(false); w = factory()->container(s_Actions[Action::TransactionMarkMenu], this); if (w) w->setEnabled(false); w = factory()->container(s_Actions[Action::TransactionContextMarkMenu], this); if (w) w->setEnabled(false); // ************* // Enabling actions based on conditions // ************* // FIXME for now it's always on, but we should only allow it, if we // can select at least a single transaction aC->action(s_Actions[Action::TransactionSelectAll])->setEnabled(true); if (!d->m_selectedTransactions.isEmpty()) { // enable 'delete transaction' only if at least one of the // selected transactions does not reference a closed account bool enable = false; KMyMoneyRegister::SelectedTransactions::const_iterator it_t; for (it_t = d->m_selectedTransactions.constBegin(); (enable == false) && (it_t != d->m_selectedTransactions.constEnd()); ++it_t) { enable = !(*it_t).transaction().id().isEmpty() && !file->referencesClosedAccount((*it_t).transaction()); } aC->action(s_Actions[Action::TransactionDelete])->setEnabled(enable); if (!d->m_transactionEditor) { QString tooltip = i18n("Duplicate the current selected transactions"); aC->action(s_Actions[Action::TransactionDuplicate])->setEnabled(d->m_myMoneyView->canDuplicateTransactions(d->m_selectedTransactions, tooltip) && !d->m_selectedTransactions[0].transaction().id().isEmpty()); aC->action(s_Actions[Action::TransactionDuplicate])->setToolTip(tooltip); if (d->m_myMoneyView->canEditTransactions(d->m_selectedTransactions, tooltip)) { aC->action(s_Actions[Action::TransactionEdit])->setEnabled(true); // editing splits is allowed only if we have one transaction selected if (d->m_selectedTransactions.count() == 1) { aC->action(s_Actions[Action::TransactionEditSplits])->setEnabled(true); } if (d->m_selectedAccount.isAssetLiability() && d->m_selectedAccount.accountType() != eMyMoney::Account::Investment) { aC->action(s_Actions[Action::TransactionCreateSchedule])->setEnabled(d->m_selectedTransactions.count() == 1); } } aC->action(s_Actions[Action::TransactionEdit])->setToolTip(tooltip); if (!d->m_selectedAccount.isClosed()) { w = factory()->container(s_Actions[Action::TransactionMoveMenu], this); if (w) w->setEnabled(true); } w = factory()->container(s_Actions[Action::TransactionMarkMenu], this); if (w) w->setEnabled(true); w = factory()->container(s_Actions[Action::TransactionContextMarkMenu], this); if (w) w->setEnabled(true); // Allow marking the transaction if at least one is selected aC->action(s_Actions[Action::TransactionToggleCleared])->setEnabled(true); aC->action(s_Actions[Action::TransactionReconciled])->setEnabled(true); aC->action(s_Actions[Action::TransactionNotReconciled])->setEnabled(true); aC->action(s_Actions[Action::TransactionToggleReconciled])->setEnabled(true); if (!d->m_accountGoto.isEmpty()) aC->action(s_Actions[Action::TransactionGoToAccount])->setEnabled(true); if (!d->m_payeeGoto.isEmpty()) aC->action(s_Actions[Action::TransactionGoToPayee])->setEnabled(true); // Matching is enabled as soon as one regular and one imported transaction is selected int matchedCount = 0; int importedCount = 0; KMyMoneyRegister::SelectedTransactions::const_iterator it; for (it = d->m_selectedTransactions.constBegin(); it != d->m_selectedTransactions.constEnd(); ++it) { if ((*it).transaction().isImported()) ++importedCount; if ((*it).split().isMatched()) ++matchedCount; } if (d->m_selectedTransactions.count() == 2 /* && aC->action(s_Actions[Action::TransactionEdit])->isEnabled() */) { aC->action(s_Actions[Action::TransactionMatch])->setEnabled(true); } if (importedCount != 0 || matchedCount != 0) aC->action(s_Actions[Action::TransactionAccept])->setEnabled(true); if (matchedCount != 0) { aC->action(s_Actions[Action::TransactionMatch])->setEnabled(true); aC->action(s_Actions[Action::TransactionMatch])->setText(i18nc("Button text for unmatch transaction", "Unmatch")); aC->action(s_Actions[Action::TransactionMatch])->setIcon(QIcon("process-stop")); } if (d->m_selectedTransactions.count() > 1) { aC->action(s_Actions[Action::TransactionCombine])->setEnabled(true); } if (d->m_selectedTransactions.count() >= 2) { int singleSplitTransactions = 0; int multipleSplitTransactions = 0; foreach (const KMyMoneyRegister::SelectedTransaction& st, d->m_selectedTransactions) { switch (st.transaction().splitCount()) { case 0: break; case 1: singleSplitTransactions++; break; default: multipleSplitTransactions++; break; } } if (singleSplitTransactions > 0 && multipleSplitTransactions == 1) { aC->action(s_Actions[Action::TransactionCopySplits])->setEnabled(true); } } if (d->m_selectedTransactions.count() >= 2) { int singleSplitTransactions = 0; int multipleSplitTransactions = 0; foreach(const KMyMoneyRegister::SelectedTransaction& st, d->m_selectedTransactions) { switch(st.transaction().splitCount()) { case 0: break; case 1: singleSplitTransactions++; break; default: multipleSplitTransactions++; break; } } if(singleSplitTransactions > 0 && multipleSplitTransactions == 1) { aC->action(s_Actions[Action::TransactionCopySplits])->setEnabled(true); } } } else { aC->action(s_Actions[Action::TransactionAssignNumber])->setEnabled(d->m_transactionEditor->canAssignNumber()); aC->action(s_Actions[Action::TransactionNew])->setEnabled(false); aC->action(s_Actions[Action::TransactionDelete])->setEnabled(false); QString reason; aC->action(s_Actions[Action::TransactionEnter])->setEnabled(d->m_transactionEditor->isComplete(reason)); //FIXME: Port to KDE4 // the next line somehow worked in KDE3 but does not have // any influence under KDE4 /// Works for me when 'reason' is set. Allan aC->action(s_Actions[Action::TransactionEnter])->setToolTip(reason); aC->action(s_Actions[Action::TransactionCancel])->setEnabled(true); } } QList accList; file->accountList(accList); QList::const_iterator it_a; QMap::const_iterator it_p = d->m_onlinePlugins.constEnd(); for (it_a = accList.constBegin(); (it_p == d->m_onlinePlugins.constEnd()) && (it_a != accList.constEnd()); ++it_a) { if (!(*it_a).onlineBankingSettings().value("provider").isEmpty()) { // check if provider is available it_p = d->m_onlinePlugins.constFind((*it_a).onlineBankingSettings().value("provider")); if (it_p != d->m_onlinePlugins.constEnd()) { QStringList protocols; (*it_p)->protocols(protocols); if (protocols.count() > 0) { aC->action(s_Actions[Action::AccountUpdateAll])->setEnabled(true); aC->action(s_Actions[Action::AccountUpdateMenu])->setEnabled(true); } } } } QBitArray skip((int)eStorage::Reference::Count); if (!d->m_selectedAccount.id().isEmpty()) { if (!file->isStandardAccount(d->m_selectedAccount.id())) { switch (d->m_selectedAccount.accountGroup()) { case eMyMoney::Account::Asset: case eMyMoney::Account::Liability: case eMyMoney::Account::Equity: aC->action(s_Actions[Action::AccountTransactionReport])->setEnabled(true); aC->action(s_Actions[Action::AccountEdit])->setEnabled(true); aC->action(s_Actions[Action::AccountDelete])->setEnabled(!file->isReferenced(d->m_selectedAccount)); aC->action(s_Actions[Action::AccountOpen])->setEnabled(true); if (d->m_selectedAccount.accountGroup() != eMyMoney::Account::Equity) { if (d->m_reconciliationAccount.id().isEmpty()) { aC->action(s_Actions[Action::AccountStartReconciliation])->setEnabled(true); aC->action(s_Actions[Action::AccountStartReconciliation])->setToolTip(i18n("Reconcile")); } else { QString tip; tip = i18n("Reconcile - disabled because you are currently reconciling %1", d->m_reconciliationAccount.name()); aC->action(s_Actions[Action::AccountStartReconciliation])->setToolTip(tip); if (!d->m_transactionEditor) { aC->action(s_Actions[Action::AccountFinishReconciliation])->setEnabled(d->m_selectedAccount.id() == d->m_reconciliationAccount.id()); aC->action(s_Actions[Action::AccountPostponeReconciliation])->setEnabled(d->m_selectedAccount.id() == d->m_reconciliationAccount.id()); } } } if (d->m_selectedAccount.accountType() == eMyMoney::Account::Investment) aC->action(s_Actions[Action::InvestmentNew])->setEnabled(true); if (d->m_selectedAccount.isClosed()) aC->action(s_Actions[Action::AccountReopen])->setEnabled(true); else enableCloseAccountAction(d->m_selectedAccount); if (!d->m_selectedAccount.onlineBankingSettings().value("provider").isEmpty()) { aC->action(s_Actions[Action::AccountOnlineUnmap])->setEnabled(true); // check if provider is available QMap::const_iterator it_p; it_p = d->m_onlinePlugins.constFind(d->m_selectedAccount.onlineBankingSettings().value("provider")); if (it_p != d->m_onlinePlugins.constEnd()) { QStringList protocols; (*it_p)->protocols(protocols); if (protocols.count() > 0) { aC->action(s_Actions[Action::AccountUpdate])->setEnabled(true); aC->action(s_Actions[Action::AccountUpdateMenu])->setEnabled(true); } } } else { aC->action(s_Actions[Action::AccountOnlineMap])->setEnabled(d->m_onlinePlugins.count() > 0); } aC->action(s_Actions[Action::AccountBalanceChart])->setEnabled(true); break; case eMyMoney::Account::Income : case eMyMoney::Account::Expense : aC->action(s_Actions[Action::CategoryEdit])->setEnabled(true); // enable delete action, if category/account itself is not referenced // by any object except accounts, because we want to allow // deleting of sub-categories. Also, we allow transactions, schedules and budgets // to be present because we can re-assign them during the delete process skip.fill(false); skip.setBit((int)eStorage::Reference::Transaction); skip.setBit((int)eStorage::Reference::Account); skip.setBit((int)eStorage::Reference::Schedule); skip.setBit((int)eStorage::Reference::Budget); aC->action(s_Actions[Action::CategoryDelete])->setEnabled(!file->isReferenced(d->m_selectedAccount, skip)); aC->action(s_Actions[Action::AccountOpen])->setEnabled(true); break; default: break; } } } if (!d->m_selectedInstitution.id().isEmpty()) { aC->action(s_Actions[Action::InstitutionEdit])->setEnabled(true); aC->action(s_Actions[Action::InstitutionDelete])->setEnabled(!file->isReferenced(d->m_selectedInstitution)); } if (!d->m_selectedInvestment.id().isEmpty()) { aC->action(s_Actions[Action::InvestmentEdit])->setEnabled(true); aC->action(s_Actions[Action::InvestmentDelete])->setEnabled(!file->isReferenced(d->m_selectedInvestment)); aC->action(s_Actions[Action::InvestmentManualPrice])->setEnabled(true); try { MyMoneySecurity security = MyMoneyFile::instance()->security(d->m_selectedInvestment.currencyId()); if (!security.value("kmm-online-source").isEmpty()) aC->action(s_Actions[Action::InvestmentOnlinePrice])->setEnabled(true); } catch (const MyMoneyException &e) { qDebug("Error retrieving security for investment %s: %s", qPrintable(d->m_selectedInvestment.name()), qPrintable(e.what())); } if (d->m_selectedInvestment.isClosed()) aC->action(s_Actions[Action::AccountReopen])->setEnabled(true); else enableCloseAccountAction(d->m_selectedInvestment); } if (!d->m_selectedSchedule.id().isEmpty()) { aC->action(s_Actions[Action::ScheduleEdit])->setEnabled(true); aC->action(s_Actions[Action::ScheduleDuplicate])->setEnabled(true); aC->action(s_Actions[Action::ScheduleDelete])->setEnabled(!file->isReferenced(d->m_selectedSchedule)); if (!d->m_selectedSchedule.isFinished()) { aC->action(s_Actions[Action::ScheduleEnter])->setEnabled(true); // a schedule with a single occurrence cannot be skipped if (d->m_selectedSchedule.occurrence() != eMyMoney::Schedule::Occurrence::Once) { aC->action(s_Actions[Action::ScheduleSkip])->setEnabled(true); } } } if (d->m_selectedPayees.count() >= 1) { aC->action(s_Actions[Action::PayeeRename])->setEnabled(d->m_selectedPayees.count() == 1); aC->action(s_Actions[Action::PayeeMerge])->setEnabled(d->m_selectedPayees.count() > 1); aC->action(s_Actions[Action::PayeeDelete])->setEnabled(true); } if (d->m_selectedTags.count() >= 1) { aC->action(s_Actions[Action::TagRename])->setEnabled(d->m_selectedTags.count() == 1); aC->action(s_Actions[Action::TagDelete])->setEnabled(true); } aC->action(s_Actions[Action::BudgetNew])->setEnabled(true); if (d->m_selectedBudgets.count() >= 1) { aC->action(s_Actions[Action::BudgetDelete])->setEnabled(true); if (d->m_selectedBudgets.count() == 1) { aC->action(s_Actions[Action::BudgetChangeYear])->setEnabled(true); aC->action(s_Actions[Action::BudgetCopy])->setEnabled(true); aC->action(s_Actions[Action::BudgetRename])->setEnabled(true); aC->action(s_Actions[Action::BudgetForecast])->setEnabled(true); } } if (!d->m_selectedCurrency.id().isEmpty()) { aC->action(s_Actions[Action::CurrencyRename])->setEnabled(true); // no need to check each transaction. accounts are enough in this case skip.fill(false); skip.setBit((int)eStorage::Reference::Transaction); aC->action(s_Actions[Action::CurrencyDelete])->setEnabled(!file->isReferenced(d->m_selectedCurrency, skip)); if (d->m_selectedCurrency.id() != file->baseCurrency().id()) aC->action(s_Actions[Action::CurrencySetBase])->setEnabled(true); } if (!d->m_selectedPrice.from().isEmpty() && d->m_selectedPrice.source() != QLatin1String("KMyMoney")) { aC->action(s_Actions[Action::PriceEdit])->setEnabled(true); aC->action(s_Actions[Action::PriceDelete])->setEnabled(true); //enable online update if it is a currency MyMoneySecurity security = MyMoneyFile::instance()->security(d->m_selectedPrice.from()); aC->action(s_Actions[Action::PriceUpdate])->setEnabled(security.isCurrency()); } } void KMyMoneyApp::slotResetSelections() { slotSelectAccount(MyMoneyAccount()); slotSelectInstitution(MyMoneyInstitution()); slotSelectInvestment(MyMoneyAccount()); slotSelectSchedule(); slotSelectCurrency(); slotSelectPrice(); slotSelectPayees(QList()); slotSelectTags(QList()); slotSelectBudget(QList()); slotSelectTransactions(KMyMoneyRegister::SelectedTransactions()); slotUpdateActions(); } void KMyMoneyApp::slotSelectCurrency() { slotSelectCurrency(MyMoneySecurity()); } void KMyMoneyApp::slotSelectCurrency(const MyMoneySecurity& currency) { d->m_selectedCurrency = currency; slotUpdateActions(); emit currencySelected(d->m_selectedCurrency); } void KMyMoneyApp::slotSelectPrice() { slotSelectPrice(MyMoneyPrice()); } void KMyMoneyApp::slotSelectPrice(const MyMoneyPrice& price) { d->m_selectedPrice = price; slotUpdateActions(); emit priceSelected(d->m_selectedPrice); } void KMyMoneyApp::slotSelectBudget(const QList& list) { d->m_selectedBudgets = list; slotUpdateActions(); emit budgetSelected(d->m_selectedBudgets); } void KMyMoneyApp::slotSelectPayees(const QList& list) { d->m_selectedPayees = list; slotUpdateActions(); emit payeesSelected(d->m_selectedPayees); } void KMyMoneyApp::slotSelectTags(const QList& list) { d->m_selectedTags = list; slotUpdateActions(); emit tagsSelected(d->m_selectedTags); } void KMyMoneyApp::slotSelectTransactions(const KMyMoneyRegister::SelectedTransactions& list) { // list can either contain a list of transactions or a single selected scheduled transaction // in the latter case, the transaction id is actually the one of the schedule. In order // to differentiate between the two, we just ask for the schedule. If we don't find one - because // we passed the id of a real transaction - then we know that fact. We use the schedule here, // because the list of schedules is kept in a cache by MyMoneyFile. This way, we save some trips // to the backend which we would have to do if we check for the transaction. d->m_selectedTransactions.clear(); d->m_selectedSchedule = MyMoneySchedule(); d->m_accountGoto.clear(); d->m_payeeGoto.clear(); if (!list.isEmpty() && !list.first().isScheduled()) { d->m_selectedTransactions = list; if (list.count() == 1) { const MyMoneySplit& sp = d->m_selectedTransactions[0].split(); if (!sp.payeeId().isEmpty()) { try { MyMoneyPayee payee = MyMoneyFile::instance()->payee(sp.payeeId()); if (!payee.name().isEmpty()) { d->m_payeeGoto = payee.id(); QString name = payee.name(); name.replace(QRegExp("&(?!&)"), "&&"); actionCollection()->action(s_Actions[Action::TransactionGoToPayee])->setText(i18n("Go to '%1'", name)); } } catch (const MyMoneyException &) { } } try { QList::const_iterator it_s; const MyMoneyTransaction& t = d->m_selectedTransactions[0].transaction(); // search the first non-income/non-expense accunt and use it for the 'goto account' const MyMoneySplit& sp = d->m_selectedTransactions[0].split(); for (it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) { if ((*it_s).id() != sp.id()) { MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId()); if (!acc.isIncomeExpense()) { // for stock accounts we show the portfolio account if (acc.isInvest()) { acc = MyMoneyFile::instance()->account(acc.parentAccountId()); } d->m_accountGoto = acc.id(); QString name = acc.name(); name.replace(QRegExp("&(?!&)"), "&&"); actionCollection()->action(s_Actions[Action::TransactionGoToAccount])->setText(i18n("Go to '%1'", name)); break; } } } } catch (const MyMoneyException &) { } } slotUpdateActions(); emit transactionsSelected(d->m_selectedTransactions); } else if (!list.isEmpty()) { slotSelectSchedule(MyMoneyFile::instance()->schedule(list.first().scheduleId())); } else { slotUpdateActions(); } // make sure, we show some neutral menu entry if we don't have an object if (d->m_payeeGoto.isEmpty()) actionCollection()->action(s_Actions[Action::TransactionGoToPayee])->setText(i18n("Go to payee")); if (d->m_accountGoto.isEmpty()) actionCollection()->action(s_Actions[Action::TransactionGoToAccount])->setText(i18n("Go to account")); } void KMyMoneyApp::slotSelectInstitution(const MyMoneyObject& institution) { if (typeid(institution) != typeid(MyMoneyInstitution)) return; d->m_selectedInstitution = dynamic_cast(institution); // qDebug("slotSelectInstitution('%s')", d->m_selectedInstitution.name().data()); slotUpdateActions(); emit institutionSelected(d->m_selectedInstitution); } void KMyMoneyApp::slotSelectAccount(const MyMoneyObject& obj) { if (typeid(obj) != typeid(MyMoneyAccount)) return; d->m_selectedAccount = MyMoneyAccount(); const MyMoneyAccount& acc = dynamic_cast(obj); if (!acc.isInvest()) d->m_selectedAccount = acc; // qDebug("slotSelectAccount('%s')", d->m_selectedAccount.name().data()); slotUpdateActions(); emit accountSelected(d->m_selectedAccount); } void KMyMoneyApp::slotSelectInvestment(const MyMoneyObject& obj) { if (typeid(obj) != typeid(MyMoneyAccount)) return; // qDebug("slotSelectInvestment('%s')", account.name().data()); d->m_selectedInvestment = MyMoneyAccount(); const MyMoneyAccount& acc = dynamic_cast(obj); if (acc.isInvest()) d->m_selectedInvestment = acc; slotUpdateActions(); emit investmentSelected(d->m_selectedInvestment); } void KMyMoneyApp::slotSelectSchedule() { slotSelectSchedule(MyMoneySchedule()); } void KMyMoneyApp::slotSelectSchedule(const MyMoneySchedule& schedule) { // qDebug("slotSelectSchedule('%s')", schedule.name().data()); d->m_selectedSchedule = schedule; slotUpdateActions(); emit scheduleSelected(d->m_selectedSchedule); } void KMyMoneyApp::slotDataChanged() { // As this method is called every time the MyMoneyFile instance // notifies a modification, it's the perfect place to start the timer if needed if (d->m_autoSaveEnabled && !d->m_autoSaveTimer->isActive()) { d->m_autoSaveTimer->setSingleShot(true); d->m_autoSaveTimer->start(d->m_autoSavePeriod * 60 * 1000); //miliseconds } updateCaption(); } void KMyMoneyApp::slotCurrencyDialog() { QPointer dlg = new KCurrencyEditDlg(this); connect(dlg, SIGNAL(selectObject(MyMoneySecurity)), this, SLOT(slotSelectCurrency(MyMoneySecurity))); connect(dlg, SIGNAL(openContextMenu(MyMoneySecurity)), this, SLOT(slotShowCurrencyContextMenu())); connect(this, SIGNAL(currencyRename()), dlg, SLOT(slotStartRename())); connect(dlg, SIGNAL(updateCurrency(QString,QString,QString)), this, SLOT(slotCurrencyUpdate(QString,QString,QString))); connect(this, SIGNAL(currencyCreated(QString)), dlg, SLOT(slotSelectCurrency(QString))); connect(dlg, SIGNAL(selectBaseCurrency(MyMoneySecurity)), this, SLOT(slotCurrencySetBase())); dlg->exec(); delete dlg; slotSelectCurrency(MyMoneySecurity()); } void KMyMoneyApp::slotPriceDialog() { QPointer dlg = new KMyMoneyPriceDlg(this); connect(dlg, SIGNAL(selectObject(MyMoneyPrice)), this, SLOT(slotSelectPrice(MyMoneyPrice))); connect(dlg, SIGNAL(openContextMenu(MyMoneyPrice)), this, SLOT(slotShowPriceContextMenu())); connect(this, SIGNAL(priceNew()), dlg, SLOT(slotNewPrice())); connect(this, SIGNAL(priceEdit()), dlg, SLOT(slotEditPrice())); connect(this, SIGNAL(priceDelete()), dlg, SLOT(slotDeletePrice())); connect(this, SIGNAL(priceOnlineUpdate()), dlg, SLOT(slotOnlinePriceUpdate())); dlg->exec(); } void KMyMoneyApp::slotFileConsistencyCheck() { d->consistencyCheck(true); updateCaption(); } void KMyMoneyApp::Private::consistencyCheck(bool alwaysDisplayResult) { KMSTATUS(i18n("Running consistency check...")); MyMoneyFileTransaction ft; try { m_consistencyCheckResult = MyMoneyFile::instance()->consistencyCheck(); ft.commit(); } catch (const MyMoneyException &e) { m_consistencyCheckResult.append(i18n("Consistency check failed: %1", e.what())); // always display the result if the check failed alwaysDisplayResult = true; } // in case the consistency check was OK, we get a single line as result // in all errneous cases, we get more than one line and force the // display of them. if (alwaysDisplayResult || m_consistencyCheckResult.size() > 1) { QString msg = i18n("The consistency check has found no issues in your data. Details are presented below."); if (m_consistencyCheckResult.size() > 1) msg = i18n("The consistency check has found some issues in your data. Details are presented below. Those issues that could not be corrected automatically need to be solved by the user."); // install a context menu for the list after the dialog is displayed QTimer::singleShot(500, q, SLOT(slotInstallConsistencyCheckContextMenu())); KMessageBox::informationList(0, msg, m_consistencyCheckResult, i18n("Consistency check result")); } // this data is no longer needed m_consistencyCheckResult.clear(); } void KMyMoneyApp::Private::copyConsistencyCheckResults() { QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(m_consistencyCheckResult.join(QLatin1String("\n"))); } void KMyMoneyApp::Private::saveConsistencyCheckResults() { QUrl fileUrl = QFileDialog::getSaveFileUrl(q); if (!fileUrl.isEmpty()) { QFile file(fileUrl.toLocalFile()); if (file.open(QFile::WriteOnly | QFile::Append | QFile::Text)) { QTextStream out(&file); out << m_consistencyCheckResult.join(QLatin1String("\n")); file.close(); } } } void KMyMoneyApp::Private::setThemedCSS() { const QStringList CSSnames {QStringLiteral("kmymoney.css"), QStringLiteral("welcome.css")}; const QString rcDir("/html/"); const QStringList defaultCSSDirs = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, rcDir, QStandardPaths::LocateDirectory); // scan the list of directories to find the ones that really // contains all files we look for QString defaultCSSDir; foreach (const auto dir, defaultCSSDirs) { defaultCSSDir = dir; foreach (const auto CSSname, CSSnames) { QFileInfo fileInfo(defaultCSSDir + CSSname); if (!fileInfo.exists()) { defaultCSSDir.clear(); break; } } if (!defaultCSSDir.isEmpty()) { break; } } // make sure we have the local directory where the themed version is stored const QString themedCSSDir = QStandardPaths::standardLocations(QStandardPaths::AppConfigLocation).first() + rcDir; QDir().mkpath(themedCSSDir); foreach (const auto CSSname, CSSnames) { const QString defaultCSSFilename = defaultCSSDir + CSSname; QFileInfo fileInfo(defaultCSSFilename); if (fileInfo.exists()) { const QString themedCSSFilename = themedCSSDir + CSSname; QFile::remove(themedCSSFilename); if (QFile::copy(defaultCSSFilename, themedCSSFilename)) { QFile cssFile (themedCSSFilename); if (cssFile.open(QIODevice::ReadWrite)) { QTextStream cssStream(&cssFile); auto cssText = cssStream.readAll(); cssText.replace(QLatin1String("./"), defaultCSSDir, Qt::CaseSensitive); cssText.replace(QLatin1String("WindowText"), KMyMoneyGlobalSettings::schemeColor(SchemeColor::WindowText).name(), Qt::CaseSensitive); cssText.replace(QLatin1String("Window"), KMyMoneyGlobalSettings::schemeColor(SchemeColor::WindowBackground).name(), Qt::CaseSensitive); cssText.replace(QLatin1String("HighlightText"), KMyMoneyGlobalSettings::schemeColor(SchemeColor::ListHighlightText).name(), Qt::CaseSensitive); cssText.replace(QLatin1String("Highlight"), KMyMoneyGlobalSettings::schemeColor(SchemeColor::ListHighlight).name(), Qt::CaseSensitive); cssText.replace(QLatin1String("black"), KMyMoneyGlobalSettings::schemeColor(SchemeColor::ListGrid).name(), Qt::CaseSensitive); cssStream.seek(0); cssStream << cssText; cssFile.close(); } } } } } void KMyMoneyApp::slotCheckSchedules() { if (KMyMoneyGlobalSettings::checkSchedule() == true) { KMSTATUS(i18n("Checking for overdue scheduled transactions...")); MyMoneyFile *file = MyMoneyFile::instance(); QDate checkDate = QDate::currentDate().addDays(KMyMoneyGlobalSettings::checkSchedulePreview()); QList scheduleList = file->scheduleList(); QList::Iterator it; - KMyMoneyUtils::EnterScheduleResultCodeE rc = KMyMoneyUtils::Enter; - for (it = scheduleList.begin(); (it != scheduleList.end()) && (rc != KMyMoneyUtils::Cancel); ++it) { + eDialogs::ScheduleResultCode rc = eDialogs::ScheduleResultCode::Enter; + for (it = scheduleList.begin(); (it != scheduleList.end()) && (rc != eDialogs::ScheduleResultCode::Cancel); ++it) { // Get the copy in the file because it might be modified by commitTransaction MyMoneySchedule schedule = file->schedule((*it).id()); if (schedule.autoEnter()) { try { while (!schedule.isFinished() && (schedule.adjustedNextDueDate() <= checkDate) - && rc != KMyMoneyUtils::Ignore - && rc != KMyMoneyUtils::Cancel) { + && rc != eDialogs::ScheduleResultCode::Ignore + && rc != eDialogs::ScheduleResultCode::Cancel) { rc = enterSchedule(schedule, true, true); schedule = file->schedule((*it).id()); // get a copy of the modified schedule } } catch (const MyMoneyException &) { } } - if (rc == KMyMoneyUtils::Ignore) { + if (rc == eDialogs::ScheduleResultCode::Ignore) { // if the current schedule was ignored then we must make sure that the user can still enter the next scheduled transaction - rc = KMyMoneyUtils::Enter; + rc = eDialogs::ScheduleResultCode::Enter; } } updateCaption(); } } void KMyMoneyApp::writeLastUsedDir(const QString& directory) { //get global config object for our app. KSharedConfigPtr kconfig = KSharedConfig::openConfig(); if (kconfig) { KConfigGroup grp = kconfig->group("General Options"); //write path entry, no error handling since its void. grp.writeEntry("LastUsedDirectory", directory); } } void KMyMoneyApp::writeLastUsedFile(const QString& fileName) { //get global config object for our app. KSharedConfigPtr kconfig = KSharedConfig::openConfig(); if (kconfig) { KConfigGroup grp = d->m_config->group("General Options"); // write path entry, no error handling since its void. // use a standard string, as fileName could contain a protocol // e.g. file:/home/thb/.... grp.writeEntry("LastUsedFile", fileName); } } QString KMyMoneyApp::readLastUsedDir() const { QString str; //get global config object for our app. KSharedConfigPtr kconfig = KSharedConfig::openConfig(); if (kconfig) { KConfigGroup grp = d->m_config->group("General Options"); //read path entry. Second parameter is the default if the setting is not found, which will be the default document path. str = grp.readEntry("LastUsedDirectory", QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); // if the path stored is empty, we use the default nevertheless if (str.isEmpty()) str = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); } return str; } QString KMyMoneyApp::readLastUsedFile() const { QString str; // get global config object for our app. KSharedConfigPtr kconfig = KSharedConfig::openConfig(); if (kconfig) { KConfigGroup grp = d->m_config->group("General Options"); // read filename entry. str = grp.readEntry("LastUsedFile", ""); } return str; } QString KMyMoneyApp::filename() const { return d->m_fileName.url(); } WebConnect* KMyMoneyApp::webConnect() const { return d->m_webConnect; } QList KMyMoneyApp::instanceList() const { QList list; #ifdef KMM_DBUS QDBusReply reply = QDBusConnection::sessionBus().interface()->registeredServiceNames(); if (reply.isValid()) { QStringList apps = reply.value(); QStringList::ConstIterator it; // build a list of service names of all running kmymoney applications without this one for (it = apps.constBegin(); it != apps.constEnd(); ++it) { // please change this method of creating a list of 'all the other kmymoney instances that are running on the system' // since assuming that D-Bus creates service names with org.kde.kmymoney-PID is an observation I don't think that it's documented somwhere if ((*it).indexOf("org.kde.kmymoney-") == 0) { uint thisProcPid = platformTools::processId(); if ((*it).indexOf(QString("org.kde.kmymoney-%1").arg(thisProcPid)) != 0) list += (*it); } } } else { qDebug("D-Bus returned the following error while obtaining instances: %s", qPrintable(reply.error().message())); } #endif return list; } void KMyMoneyApp::slotEquityPriceUpdate() { QPointer dlg = new KEquityPriceUpdateDlg(this); if (dlg->exec() == QDialog::Accepted && dlg != 0) dlg->storePrices(); delete dlg; } void KMyMoneyApp::webConnect(const QString& sourceUrl, const QByteArray& asn_id) { // // Web connect attempts to go through the known importers and see if the file // can be importing using that method. If so, it will import it using that // plugin // Q_UNUSED(asn_id) d->m_importUrlsQueue.enqueue(sourceUrl); // only start processing if this is the only import so far if (d->m_importUrlsQueue.count() == 1) { while (!d->m_importUrlsQueue.isEmpty()) { // get the value of the next item from the queue // but leave it on the queue for now QString url = d->m_importUrlsQueue.head(); // Bring this window to the forefront. This method was suggested by // Lubos Lunak of the KDE core development team. // TODO: port KF5 (WebConnect) //KStartupInfo::setNewStartupId(this, asn_id); // Make sure we have an open file if (! d->m_myMoneyView->fileOpen() && KMessageBox::warningContinueCancel(kmymoney, i18n("You must first select a KMyMoney file before you can import a statement.")) == KMessageBox::Continue) kmymoney->slotFileOpen(); // only continue if the user really did open a file. if (d->m_myMoneyView->fileOpen()) { KMSTATUS(i18n("Importing a statement via Web Connect")); // remove the statement files d->unlinkStatementXML(); QMap::const_iterator it_plugin = d->m_importerPlugins.constBegin(); while (it_plugin != d->m_importerPlugins.constEnd()) { if ((*it_plugin)->isMyFormat(url)) { QList statements; if (!(*it_plugin)->import(url)) { KMessageBox::error(this, i18n("Unable to import %1 using %2 plugin. The plugin returned the following error: %3", url, (*it_plugin)->formatName(), (*it_plugin)->lastError()), i18n("Importing error")); } break; } ++it_plugin; } // If we did not find a match, try importing it as a KMM statement file, // which is really just for testing. the statement file is not exposed // to users. if (it_plugin == d->m_importerPlugins.constEnd()) if (MyMoneyStatement::isStatementFile(url)) slotStatementImport(url); } // remove the current processed item from the queue d->m_importUrlsQueue.dequeue(); } } } void KMyMoneyApp::slotEnableMessages() { KMessageBox::enableAllMessages(); KMessageBox::information(this, i18n("All messages have been enabled."), i18n("All messages")); } void KMyMoneyApp::createInterfaces() { // Sets up the plugin interface KMyMoneyPlugin::pluginInterfaces().importInterface = new KMyMoneyPlugin::KMMImportInterface(this, this); KMyMoneyPlugin::pluginInterfaces().statementInterface = new KMyMoneyPlugin::KMMStatementInterface(this, this); KMyMoneyPlugin::pluginInterfaces().viewInterface = new KMyMoneyPlugin::KMMViewInterface(this, d->m_myMoneyView, this); // setup the calendar interface for schedules MyMoneySchedule::setProcessingCalendar(this); } void KMyMoneyApp::loadPlugins() { Q_ASSERT(!d->m_pluginLoader); d->m_pluginLoader = new KMyMoneyPlugin::PluginLoader(this); //! @todo Junior Job: Improve the config read system KSharedConfigPtr config = KSharedConfig::openConfig(); KConfigGroup group{ config->group("Plugins") }; const auto plugins = KPluginLoader::findPlugins("kmymoney"); d->m_pluginLoader->addPluginInfo(plugins); for (const KPluginMetaData & pluginData : plugins) { // Only load plugins which are enabled and have the right serviceType. Other serviceTypes are loaded on demand. if (isPluginEnabled(pluginData, group)) slotPluginLoad(pluginData); } connect(d->m_pluginLoader, &KMyMoneyPlugin::PluginLoader::pluginEnabled, this, &KMyMoneyApp::slotPluginLoad); connect(d->m_pluginLoader, &KMyMoneyPlugin::PluginLoader::pluginDisabled, this, &KMyMoneyApp::slotPluginUnload); } void KMyMoneyApp::unloadPlugins() { Q_ASSERT(d->m_pluginLoader); delete d->m_pluginLoader; } inline bool KMyMoneyApp::isPluginEnabled(const KPluginMetaData& metaData, const KConfigGroup& configGroup) { //! @fixme: there is a function in KMyMoneyPlugin::PluginLoader which has to have the same content if (metaData.serviceTypes().contains("KMyMoney/Plugin")) { const QString keyName{metaData.name() + "Enabled"}; if (configGroup.hasKey(keyName)) return configGroup.readEntry(keyName, true); return metaData.isEnabledByDefault(); } return false; } void KMyMoneyApp::slotPluginLoad(const KPluginMetaData& metaData) { std::unique_ptr loader{new QPluginLoader{metaData.fileName()}}; QObject* plugin = loader->instance(); if (!plugin) { qWarning("Could not load plugin '%s', error: %s", qPrintable(metaData.fileName()), qPrintable(loader->errorString())); return; } if ( d->m_plugins.contains(metaData.fileName()) ) { /** @fixme Handle a reload e.g. objectNames are equal but the object are different (plugin != d->m_plugins[plugin->objectName()]) * Also it could be usefull to drop the dependence on objectName() */ /* Note: there is nothing to delete here because if the plugin was loaded already, plugin points to the same object as the previously loaded one. */ return; } KMyMoneyPlugin::Plugin* kmmPlugin = qobject_cast(plugin); if (!kmmPlugin) { qWarning("Could not load plugin '%s'.", qPrintable(metaData.fileName())); return; } // check for online plugin KMyMoneyPlugin::OnlinePlugin* op = dynamic_cast(plugin); // check for extended online plugin KMyMoneyPlugin::OnlinePluginExtended* ope = dynamic_cast(plugin); // check for importer plugin KMyMoneyPlugin::ImporterPlugin* ip = dynamic_cast(plugin); // Tell the plugin it is about to get plugged kmmPlugin->plug(); // plug the plugin guiFactory()->addClient(kmmPlugin); d->m_plugins[metaData.fileName()] = kmmPlugin; if (op) d->m_onlinePlugins[plugin->objectName()] = op; if (ope) onlineJobAdministration::instance()->addPlugin(plugin->objectName(), ope); if (ip) d->m_importerPlugins[plugin->objectName()] = ip; slotUpdateActions(); } void KMyMoneyApp::slotPluginUnload(const KPluginMetaData& metaData) { KMyMoneyPlugin::Plugin* plugin = d->m_plugins[metaData.fileName()]; // Remove and test if the plugin was actually loaded if (!d->m_plugins.remove(metaData.fileName()) || plugin == nullptr) return; // check for online plugin KMyMoneyPlugin::OnlinePlugin* op = dynamic_cast(plugin); // check for importer plugin KMyMoneyPlugin::ImporterPlugin* ip = dynamic_cast(plugin); // unplug the plugin guiFactory()->removeClient(plugin); if (op) d->m_onlinePlugins.remove(plugin->objectName()); if (ip) d->m_importerPlugins.remove(plugin->objectName()); plugin->unplug(); slotUpdateActions(); } void KMyMoneyApp::slotAutoSave() { if (!d->m_inAutoSaving) { // store the focus widget so we can restore it after save QPointer focusWidget = qApp->focusWidget(); d->m_inAutoSaving = true; KMSTATUS(i18n("Auto saving...")); //calls slotFileSave if needed, and restart the timer //it the file is not saved, reinitializes the countdown. if (d->m_myMoneyView->dirty() && d->m_autoSaveEnabled) { if (!slotFileSave() && d->m_autoSavePeriod > 0) { d->m_autoSaveTimer->setSingleShot(true); d->m_autoSaveTimer->start(d->m_autoSavePeriod * 60 * 1000); } } d->m_inAutoSaving = false; if (focusWidget && focusWidget != qApp->focusWidget()) { // we have a valid focus widget so restore it focusWidget->setFocus(); } } } void KMyMoneyApp::slotDateChanged() { QDateTime dt = QDateTime::currentDateTime(); QDateTime nextDay(QDate(dt.date().addDays(1)), QTime(0, 0, 0)); // +1 is to make sure that we're already in the next day when the // signal is sent (this way we also avoid setting the timer to 0) QTimer::singleShot((dt.secsTo(nextDay) + 1)*1000, this, SLOT(slotDateChanged())); d->m_myMoneyView->slotRefreshViews(); } const MyMoneyAccount& KMyMoneyApp::account(const QString& key, const QString& value) const { QList list; QList::const_iterator it_a; MyMoneyFile::instance()->accountList(list); QString accId; for (it_a = list.constBegin(); it_a != list.constEnd(); ++it_a) { // search in the account's kvp container const QString& accountKvpValue = (*it_a).value(key); // search in the account's online settings kvp container const QString& onlineSettingsKvpValue = (*it_a).onlineBankingSettings().value(key); if (accountKvpValue.contains(value) || onlineSettingsKvpValue.contains(value)) { if(accId.isEmpty()) { accId = (*it_a).id(); } } if (accountKvpValue == value || onlineSettingsKvpValue == value) { accId = (*it_a).id(); break; } } // return the account found or an empty element return MyMoneyFile::instance()->account(accId); } void KMyMoneyApp::setAccountOnlineParameters(const MyMoneyAccount& _acc, const MyMoneyKeyValueContainer& kvps) { MyMoneyFileTransaction ft; try { MyMoneyAccount acc = MyMoneyFile::instance()->account(_acc.id()); acc.setOnlineBankingSettings(kvps); MyMoneyFile::instance()->modifyAccount(acc); ft.commit(); } catch (const MyMoneyException &e) { KMessageBox::detailedSorry(0, i18n("Unable to setup online parameters for account '%1'", _acc.name()), e.what()); } } void KMyMoneyApp::slotAccountUnmapOnline() { // no account selected if (d->m_selectedAccount.id().isEmpty()) return; // not a mapped account if (d->m_selectedAccount.onlineBankingSettings().value("provider").isEmpty()) return; if (KMessageBox::warningYesNo(this, QString("%1").arg(i18n("Do you really want to remove the mapping of account %1 to an online account? Depending on the details of the online banking method used, this action cannot be reverted.", d->m_selectedAccount.name())), i18n("Remove mapping to online account")) == KMessageBox::Yes) { MyMoneyFileTransaction ft; try { d->m_selectedAccount.setOnlineBankingSettings(MyMoneyKeyValueContainer()); // delete the kvp that is used in MyMoneyStatementReader too // we should really get rid of it, but since I don't know what it // is good for, I'll keep it around. (ipwizard) d->m_selectedAccount.deletePair("StatementKey"); MyMoneyFile::instance()->modifyAccount(d->m_selectedAccount); ft.commit(); // The mapping could disable the online task system onlineJobAdministration::instance()->updateOnlineTaskProperties(); } catch (const MyMoneyException &e) { KMessageBox::error(this, i18n("Unable to unmap account from online account: %1", e.what())); } } } void KMyMoneyApp::slotAccountMapOnline() { // no account selected if (d->m_selectedAccount.id().isEmpty()) return; // already an account mapped if (!d->m_selectedAccount.onlineBankingSettings().value("provider").isEmpty()) return; // check if user tries to map a brokerageAccount if (d->m_selectedAccount.name().contains(i18n(" (Brokerage)"))) { if (KMessageBox::warningContinueCancel(this, i18n("You try to map a brokerage account to an online account. This is usually not advisable. In general, the investment account should be mapped to the online account. Please cancel if you intended to map the investment account, continue otherwise"), i18n("Mapping brokerage account")) == KMessageBox::Cancel) { return; } } // if we have more than one provider let the user select the current provider QString provider; QMap::const_iterator it_p; switch (d->m_onlinePlugins.count()) { case 0: break; case 1: provider = d->m_onlinePlugins.begin().key(); break; default: { QMenu popup(this); popup.setTitle(i18n("Select online banking plugin")); // Populate the pick list with all the provider for (it_p = d->m_onlinePlugins.constBegin(); it_p != d->m_onlinePlugins.constEnd(); ++it_p) { popup.addAction(it_p.key())->setData(it_p.key()); } QAction *item = popup.actions()[0]; if (item) { popup.setActiveAction(item); } // cancelled if ((item = popup.exec(QCursor::pos(), item)) == 0) { return; } provider = item->data().toString(); } break; } if (provider.isEmpty()) return; // find the provider it_p = d->m_onlinePlugins.constFind(provider); if (it_p != d->m_onlinePlugins.constEnd()) { // plugin found, call it MyMoneyKeyValueContainer settings; if ((*it_p)->mapAccount(d->m_selectedAccount, settings)) { settings["provider"] = provider; MyMoneyAccount acc(d->m_selectedAccount); acc.setOnlineBankingSettings(settings); MyMoneyFileTransaction ft; try { MyMoneyFile::instance()->modifyAccount(acc); ft.commit(); // The mapping could enable the online task system onlineJobAdministration::instance()->updateOnlineTaskProperties(); } catch (const MyMoneyException &e) { KMessageBox::error(this, i18n("Unable to map account to online account: %1", e.what())); } } } } void KMyMoneyApp::slotAccountUpdateOnlineAll() { QList accList; MyMoneyFile::instance()->accountList(accList); QList::iterator it_a; QMap::const_iterator it_p; d->m_statementResults.clear(); d->m_collectingStatements = true; // remove all those from the list, that don't have a 'provider' or the // provider is not currently present for (it_a = accList.begin(); it_a != accList.end();) { if ((*it_a).onlineBankingSettings().value("provider").isEmpty() || d->m_onlinePlugins.find((*it_a).onlineBankingSettings().value("provider")) == d->m_onlinePlugins.end()) { it_a = accList.erase(it_a); } else ++it_a; } QVector disabledActions {Action::AccountUpdate, Action::AccountUpdateMenu, Action::AccountUpdateAll}; foreach (const auto a, disabledActions) actionCollection()->action(s_Actions.value(a))->setEnabled(false); // now work on the remaining list of accounts int cnt = accList.count() - 1; for (it_a = accList.begin(); it_a != accList.end(); ++it_a) { it_p = d->m_onlinePlugins.constFind((*it_a).onlineBankingSettings().value("provider")); (*it_p)->updateAccount(*it_a, cnt != 0); --cnt; } d->m_collectingStatements = false; if (!d->m_statementResults.isEmpty()) KMessageBox::informationList(this, i18n("The statements have been processed with the following results:"), d->m_statementResults, i18n("Statement stats")); // re-enable the disabled actions slotUpdateActions(); } void KMyMoneyApp::slotAccountUpdateOnline() { // no account selected if (d->m_selectedAccount.id().isEmpty()) return; // no online account mapped if (d->m_selectedAccount.onlineBankingSettings().value("provider").isEmpty()) return; QVector disabledActions {Action::AccountUpdate, Action::AccountUpdateMenu, Action::AccountUpdateAll}; foreach (const auto a, disabledActions) actionCollection()->action(s_Actions.value(a))->setEnabled(false); // find the provider QMap::const_iterator it_p; it_p = d->m_onlinePlugins.constFind(d->m_selectedAccount.onlineBankingSettings().value("provider")); if (it_p != d->m_onlinePlugins.constEnd()) { // plugin found, call it d->m_collectingStatements = true; d->m_statementResults.clear(); (*it_p)->updateAccount(d->m_selectedAccount); d->m_collectingStatements = false; if (!d->m_statementResults.isEmpty()) KMessageBox::informationList(this, i18n("The statements have been processed with the following results:"), d->m_statementResults, i18n("Statement stats")); } // re-enable the disabled actions slotUpdateActions(); } void KMyMoneyApp::slotNewOnlineTransfer() { kOnlineTransferForm *transferForm = new kOnlineTransferForm(this); if (!d->m_selectedAccount.id().isEmpty()) { transferForm->setCurrentAccount(d->m_selectedAccount.id()); } connect(transferForm, SIGNAL(rejected()), transferForm, SLOT(deleteLater())); connect(transferForm, SIGNAL(acceptedForSave(onlineJob)), this, SLOT(slotOnlineJobSave(onlineJob))); connect(transferForm, SIGNAL(acceptedForSend(onlineJob)), this, SLOT(slotOnlineJobSend(onlineJob))); connect(transferForm, SIGNAL(accepted()), transferForm, SLOT(deleteLater())); transferForm->show(); } void KMyMoneyApp::slotEditOnlineJob(const QString jobId) { try { const onlineJob constJob = MyMoneyFile::instance()->getOnlineJob(jobId); slotEditOnlineJob(constJob); } catch (MyMoneyException&) { // Prevent a crash in very rare cases } } void KMyMoneyApp::slotEditOnlineJob(onlineJob job) { try { slotEditOnlineJob(onlineJobTyped(job)); } catch (MyMoneyException&) { } } void KMyMoneyApp::slotEditOnlineJob(const onlineJobTyped job) { kOnlineTransferForm *transferForm = new kOnlineTransferForm(this); transferForm->setOnlineJob(job); connect(transferForm, SIGNAL(rejected()), transferForm, SLOT(deleteLater())); connect(transferForm, SIGNAL(acceptedForSave(onlineJob)), this, SLOT(slotOnlineJobSave(onlineJob))); connect(transferForm, SIGNAL(acceptedForSend(onlineJob)), this, SLOT(slotOnlineJobSend(onlineJob))); connect(transferForm, SIGNAL(accepted()), transferForm, SLOT(deleteLater())); transferForm->show(); } void KMyMoneyApp::slotOnlineJobSave(onlineJob job) { MyMoneyFileTransaction fileTransaction; if (job.id() == MyMoneyObject::emptyId()) MyMoneyFile::instance()->addOnlineJob(job); else MyMoneyFile::instance()->modifyOnlineJob(job); fileTransaction.commit(); } /** @todo when onlineJob queue is used, continue here */ void KMyMoneyApp::slotOnlineJobSend(onlineJob job) { MyMoneyFileTransaction fileTransaction; if (job.id() == MyMoneyObject::emptyId()) MyMoneyFile::instance()->addOnlineJob(job); else MyMoneyFile::instance()->modifyOnlineJob(job); fileTransaction.commit(); QList jobList; jobList.append(job); slotOnlineJobSend(jobList); } void KMyMoneyApp::slotOnlineJobSend(QList jobs) { MyMoneyFile *const kmmFile = MyMoneyFile::instance(); QMultiMap jobsByPlugin; // Sort jobs by online plugin & lock them foreach (onlineJob job, jobs) { Q_ASSERT(job.id() != MyMoneyObject::emptyId()); // find the provider const MyMoneyAccount originAcc = job.responsibleMyMoneyAccount(); job.setLock(); job.addJobMessage(onlineJobMessage(onlineJobMessage::debug, "KMyMoneyApp::slotOnlineJobSend", "Added to queue for plugin '" + originAcc.onlineBankingSettings().value("provider") + '\'')); MyMoneyFileTransaction fileTransaction; kmmFile->modifyOnlineJob(job); fileTransaction.commit(); jobsByPlugin.insert(originAcc.onlineBankingSettings().value("provider"), job); } // Send onlineJobs to plugins QList usedPlugins = jobsByPlugin.keys(); std::sort(usedPlugins.begin(), usedPlugins.end()); const QList::iterator newEnd = std::unique(usedPlugins.begin(), usedPlugins.end()); usedPlugins.erase(newEnd, usedPlugins.end()); foreach (const QString& pluginKey, usedPlugins) { QMap::const_iterator it_p = d->m_onlinePlugins.constFind(pluginKey); if (it_p != d->m_onlinePlugins.constEnd()) { // plugin found, call it KMyMoneyPlugin::OnlinePluginExtended *pluginExt = dynamic_cast< KMyMoneyPlugin::OnlinePluginExtended* >(*it_p); if (pluginExt == 0) { qWarning("Job given for plugin which is not an extended plugin"); continue; } //! @fixme remove debug message qDebug() << "Sending " << jobsByPlugin.count(pluginKey) << " job(s) to online plugin " << pluginKey; QList jobsToExecute = jobsByPlugin.values(pluginKey); QList executedJobs = jobsToExecute; pluginExt->sendOnlineJob(executedJobs); // Save possible changes of the online job and remove lock MyMoneyFileTransaction fileTransaction; foreach (onlineJob job, executedJobs) { fileTransaction.restart(); job.setLock(false); kmmFile->modifyOnlineJob(job); fileTransaction.commit(); } if (Q_UNLIKELY(executedJobs.size() != jobsToExecute.size())) { // OnlinePlugin did not return all jobs qWarning() << "Error saving send online tasks. After restart you should see at minimum all successfully executed jobs marked send. Imperfect plugin: " << pluginExt->objectName(); } } else { qWarning() << "Error, got onlineJob for an account without online plugin."; /** @FIXME can this actually happen? */ } } } void KMyMoneyApp::slotRemoveJob() { } void KMyMoneyApp::slotEditJob() { } void KMyMoneyApp::slotOnlineJobLog() { QStringList jobIds = d->m_myMoneyView->getOnlineJobOutbox()->selectedOnlineJobs(); slotOnlineJobLog(jobIds); } void KMyMoneyApp::slotOnlineJobLog(const QStringList& onlineJobIds) { onlineJobMessagesView *const dialog = new onlineJobMessagesView(); onlineJobMessagesModel *const model = new onlineJobMessagesModel(dialog); model->setOnlineJob(MyMoneyFile::instance()->getOnlineJob(onlineJobIds.first())); dialog->setModel(model); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); // Note: Objects are not deleted here, Qt's parent-child system has to do that. } void KMyMoneyApp::setHolidayRegion(const QString& holidayRegion) { #ifdef KF5Holidays_FOUND //since the cost of updating the cache is now not negligible //check whether the region has been modified if (!d->m_holidayRegion || d->m_holidayRegion->regionCode() != holidayRegion) { // Delete the previous holidayRegion before creating a new one. delete d->m_holidayRegion; // Create a new holidayRegion. d->m_holidayRegion = new KHolidays::HolidayRegion(holidayRegion); //clear and update the holiday cache preloadHolidays(); } #else Q_UNUSED(holidayRegion); #endif } bool KMyMoneyApp::isProcessingDate(const QDate& date) const { #ifdef KF5Holidays_FOUND if (!d->m_processingDays.testBit(date.dayOfWeek())) return false; if (!d->m_holidayRegion || !d->m_holidayRegion->isValid()) return true; //check first whether it's already in cache if (d->m_holidayMap.contains(date)) { return d->m_holidayMap.value(date, true); } else { bool processingDay = !d->m_holidayRegion->isHoliday(date); d->m_holidayMap.insert(date, processingDay); return processingDay; } #else Q_UNUSED(date); return true; #endif } void KMyMoneyApp::preloadHolidays() { #ifdef KF5Holidays_FOUND //clear the cache before loading d->m_holidayMap.clear(); //only do this if it is a valid region if (d->m_holidayRegion && d->m_holidayRegion->isValid()) { //load holidays for the forecast days plus 1 cycle, to be on the safe side int forecastDays = KMyMoneyGlobalSettings::forecastDays() + KMyMoneyGlobalSettings::forecastAccountCycle(); QDate endDate = QDate::currentDate().addDays(forecastDays); //look for holidays for the next 2 years as a minimum. That should give a good margin for the cache if (endDate < QDate::currentDate().addYears(2)) endDate = QDate::currentDate().addYears(2); KHolidays::Holiday::List holidayList = d->m_holidayRegion->holidays(QDate::currentDate(), endDate); KHolidays::Holiday::List::const_iterator holiday_it; for (holiday_it = holidayList.constBegin(); holiday_it != holidayList.constEnd(); ++holiday_it) { for (QDate holidayDate = (*holiday_it).observedStartDate(); holidayDate <= (*holiday_it).observedEndDate(); holidayDate = holidayDate.addDays(1)) d->m_holidayMap.insert(holidayDate, false); } for (QDate date = QDate::currentDate(); date <= endDate; date = date.addDays(1)) { //if it is not a processing day, set it to false if (!d->m_processingDays.testBit(date.dayOfWeek())) { d->m_holidayMap.insert(date, false); } else if (!d->m_holidayMap.contains(date)) { //if it is not a holiday nor a weekend, it is a processing day d->m_holidayMap.insert(date, true); } } } #endif } KMStatus::KMStatus(const QString &text) { m_prevText = kmymoney->slotStatusMsg(text); } KMStatus::~KMStatus() { kmymoney->slotStatusMsg(m_prevText); } void KMyMoneyApp::Private::unlinkStatementXML() { QDir d(KMyMoneySettings::logPath(), "kmm-statement*"); for (uint i = 0; i < d.count(); ++i) { qDebug("Remove %s", qPrintable(d[i])); d.remove(KMyMoneySettings::logPath() + QString("/%1").arg(d[i])); } m_statementXMLindex = 0; } void KMyMoneyApp::Private::closeFile() { q->slotSelectAccount(MyMoneyAccount()); q->slotSelectInstitution(MyMoneyInstitution()); q->slotSelectInvestment(MyMoneyAccount()); q->slotSelectSchedule(); q->slotSelectCurrency(); q->slotSelectBudget(QList()); q->slotSelectPayees(QList()); q->slotSelectTags(QList()); q->slotSelectTransactions(KMyMoneyRegister::SelectedTransactions()); m_reconciliationAccount = MyMoneyAccount(); m_myMoneyView->finishReconciliation(m_reconciliationAccount); m_myMoneyView->closeFile(); m_fileName = QUrl(); q->updateCaption(); // just create a new balance warning object delete m_balanceWarning; m_balanceWarning = new KBalanceWarning(q); emit q->fileLoaded(m_fileName); } diff --git a/kmymoney/kmymoney.h b/kmymoney/kmymoney.h index b129abf05..6232bd60f 100644 --- a/kmymoney/kmymoney.h +++ b/kmymoney/kmymoney.h @@ -1,1470 +1,1473 @@ /*************************************************************************** kmymoney.h ------------------- copyright : (C) 2000-2001 by Michael Edwardes ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #ifndef KMYMONEY_H #define KMYMONEY_H // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes #include #include "kmymoneyutils.h" #include "mymoneyaccount.h" #include "mymoney/onlinejob.h" #include "onlinejobtyped.h" #include "mymoneykeyvaluecontainer.h" #include "mymoneymoney.h" #include "selectedtransaction.h" class QResizeEvent; class KPluginMetaData; class MyMoneyObject; class MyMoneyInstitution; class MyMoneyAccount; class MyMoneySecurity; class MyMoneyBudget; class MyMoneyPayee; class MyMoneyPrice; class MyMoneyStatement; class MyMoneyTag; class MyMoneySplit; class MyMoneyTransaction; class WebConnect; class creditTransfer; template class onlineJobTyped; enum class Action { FileOpenDatabase, FileSaveAsDatabase, FileBackup, FileImportGNC, FileImportStatement, FileImportTemplate, FileExportTemplate, #ifdef KMM_DEBUG FileDump, #endif FilePersonalData, FileInformation, EditFindTransaction, ViewTransactionDetail, ViewHideReconciled, ViewHideCategories, ViewShowAll, InstitutionNew, InstitutionEdit, InstitutionDelete, AccountNew, AccountOpen, AccountStartReconciliation, AccountFinishReconciliation, AccountPostponeReconciliation, AccountEdit, AccountDelete, AccountClose, AccountReopen, AccountTransactionReport, AccountBalanceChart, AccountUpdateMenu, AccountOnlineMap, AccountOnlineUnmap, AccountUpdate, AccountUpdateAll, AccountCreditTransfer, CategoryNew, CategoryEdit, CategoryDelete, ToolCurrencies, ToolPrices, ToolUpdatePrices, ToolConsistency, ToolPerformance, ToolSQL, ToolCalculator, SettingsAllMessages, HelpShow, TransactionNew, TransactionEdit, TransactionEnter, TransactionEditSplits, TransactionCancel, TransactionDelete, TransactionDuplicate, TransactionMatch, TransactionAccept, TransactionToggleReconciled, TransactionToggleCleared, TransactionReconciled, TransactionNotReconciled, TransactionSelectAll, TransactionGoToAccount, TransactionGoToPayee, TransactionCreateSchedule, TransactionAssignNumber, TransactionCombine, TransactionCopySplits, TransactionMoveMenu, TransactionMarkMenu, TransactionContextMarkMenu, InvestmentNew, InvestmentEdit, InvestmentDelete, InvestmentOnlinePrice, InvestmentManualPrice, ScheduleNew, ScheduleEdit, ScheduleDelete, ScheduleDuplicate, ScheduleEnter, ScheduleSkip, PayeeNew, PayeeRename, PayeeDelete, PayeeMerge, TagNew, TagRename, TagDelete, BudgetNew, BudgetRename, BudgetDelete, BudgetCopy, BudgetChangeYear, BudgetForecast, CurrencyNew, CurrencyRename, CurrencyDelete, CurrencySetBase, PriceNew, PriceDelete, PriceUpdate, PriceEdit, #ifdef KMM_DEBUG WizardNewUser, DebugTraces, #endif DebugTimers, OnlineJobDelete, OnlineJobEdit, OnlineJobLog }; +namespace eDialogs { enum class ScheduleResultCode; } + inline uint qHash(const Action key, uint seed) { return ::qHash(static_cast(key), seed); } /*! \mainpage KMyMoney Main Page for API documentation. * * \section intro Introduction * * This is the API documentation for KMyMoney. It should be used as a reference * for KMyMoney developers and users who wish to see how KMyMoney works. This * documentation will be kept up-to-date as development progresses and should be * read for new features that have been developed in KMyMoney. */ /** * The base class for KMyMoney application windows. It sets up the main * window and reads the config file as well as providing a menubar, toolbar * and statusbar. * * @see KMyMoneyView * * @author Michael Edwardes 2000-2001 * @author Thomas Baumgart 2006-2008 * * @short Main application class. */ class KMyMoneyApp : public KXmlGuiWindow, public IMyMoneyProcessingCalendar { Q_OBJECT private slots: /** * Keep track of objects that are destroyed by external events */ void slotObjectDestroyed(QObject* o); /** * Add a context menu to the list used by KMessageBox::informationList to display the consistency check results. */ void slotInstallConsistencyCheckContextMenu(); /** * Handle the context menu of the list used by KMessageBox::informationList to display the consistency check results. */ void slotShowContextMenuForConsistencyCheck(const QPoint &); protected slots: void slotFileSaveAsFilterChanged(const QString& filter); /** * This slot is intended to be used as part of auto saving. This is used when the * QTimer emits the timeout signal and simply checks that the file is dirty (has * received modifications to its contents), and call the appropriate method to * save the file. Furthermore, re-starts the timer (possibly not needed). * @author mvillarino 2005 * @see KMyMoneyApp::slotDataChanged() */ void slotAutoSave(); /** * This slot re-enables all message for which the "Don't show again" * option had been selected. */ void slotEnableMessages(); /** * Called when the user asks for file information. */ void slotFileFileInfo(); /** * Called to run performance test. */ void slotPerformanceTest(); /** * Called to generate the sql to create kmymoney database tables etc. */ void slotGenerateSql(); #ifdef KMM_DEBUG /** * Debugging only: turn on/off traces */ void slotToggleTraces(); #endif /** * Debugging only: turn on/off timers */ void slotToggleTimers(); /** * Called when the user asks for the personal information. */ void slotFileViewPersonal(); /** * Opens a file selector dialog for the user to choose an existing OFX * file from the file system to be imported. This slot is expected to * be called from the UI. */ void slotGncImport(); /** * Open a dialog with a chart of the balance for the currently selected * account (m_selectedAccount). Return once the dialog is closed. Don't do * anything if no account is selected or charts are not available. */ void slotAccountChart(); /** * Opens a file selector dialog for the user to choose an existing KMM * statement file from the file system to be imported. This is for testing * only. KMM statement files are not designed to be exposed to the user. */ void slotStatementImport(); void slotLoadAccountTemplates(); void slotSaveAccountTemplates(); /** * Open up the application wide settings dialog. * * @see KSettingsDlg */ void slotSettings(); /** * Called to show credits window. */ void slotShowCredits(); /** * Called when the user wishes to backup the current file */ void slotBackupFile(); /** * Perform mount operation before making a backup of the current file */ void slotBackupMount(); /** * Perform the backup write operation */ bool slotBackupWriteFile(); /** * Perform unmount operation after making a backup of the current file */ void slotBackupUnmount(); /** * Finish backup of the current file */ void slotBackupFinish(); /** * Handle events on making a backup of the current file */ void slotBackupHandleEvents(); void slotShowTipOfTheDay(); void slotShowPreviousView(); void slotShowNextView(); /** * Brings up a dialog to let the user search for specific transaction(s). It then * opens a results window to display those transactions. */ void slotFindTransaction(); /** * Destroys a possibly open the search dialog */ void slotCloseSearchDialog(); /** * Brings up the new category editor and saves the information. * The dialog will be preset with the name. The parent defaults to * MyMoneyFile::expense() * * @param name Name of the account to be created. Could include a full hierarchy * @param id reference to storage which will receive the id after successful creation * * @note Typically, this slot can be connected to the * StdTransactionEditor::createCategory(const QString&, QString&) or * KMyMoneyCombo::createItem(const QString&, QString&) signal. */ void slotCategoryNew(const QString& name, QString& id); /** * Calls the print logic for the current view */ void slotPrintView(); - /** - * Create a new investment - */ - void slotInvestmentNew(); - - /** - * Create a new investment in a given @p parent investment account - */ - void slotInvestmentNew(MyMoneyAccount& account, const MyMoneyAccount& parent); - - /** - * This slot opens the investment editor to edit the currently - * selected investment if possible - */ - void slotInvestmentEdit(); - - /** - * Deletes the current selected investment. - */ - void slotInvestmentDelete(); - /** * Performs online update for currently selected investment */ void slotOnlinePriceUpdate(); /** * Performs manual update for currently selected investment */ void slotManualPriceUpdate(); /** * Call this slot, if any configuration parameter has changed */ void slotUpdateConfiguration(); - /** - */ - bool slotPayeeNew(const QString& newnameBase, QString& id); - void slotPayeeNew(); - /** */ void slotPayeeDelete(); /** * Slot that merges two or more selected payess into a new payee */ void slotPayeeMerge(); /** */ void slotBudgetNew(); /** */ void slotBudgetDelete(); /** */ void slotBudgetCopy(); /** */ void slotBudgetChangeYear(); /** */ void slotBudgetForecast(); /** */ void slotCurrencyNew(); /** */ void slotCurrencyUpdate(const QString ¤cyId, const QString& currencyName, const QString& currencyTradingSymbol); /** */ void slotCurrencyDelete(); /** */ void slotCurrencySetBase(); /** * This slot is used to start new features during the development cycle */ void slotNewFeature(); /** */ void slotTransactionsNew(); /** */ void slotTransactionsEdit(); /** */ void slotTransactionsEditSplits(); /** */ void slotTransactionsDelete(); /** */ void slotTransactionsEnter(); /** */ void slotTransactionsCancel(); /** */ void slotTransactionsCancelOrEnter(bool& okToSelect); /** */ void slotTransactionDuplicate(); /** */ void slotToggleReconciliationFlag(); /** */ void slotMarkTransactionCleared(); /** */ void slotMarkTransactionReconciled(); /** */ void slotMarkTransactionNotReconciled(); /** */ void slotTransactionGotoAccount(); /** */ void slotTransactionGotoPayee(); /** */ void slotTransactionCreateSchedule(); /** */ void slotTransactionAssignNumber(); /** */ void slotTransactionCombine(); /** * This method takes the selected splits and checks that only one transaction (src) * has more than one split and all others have only a single one. It then copies the * splits of the @b src transaction to all others. */ void slotTransactionCopySplits(); /** * Accept the selected transactions that are marked as 'imported' and remove the flag */ void slotTransactionsAccept(); /** * This slot triggers an update of all views and restarts * a single shot timer to call itself again at beginning of * the next day. */ void slotDateChanged(); /** * This slot will be called when the engine data changed * and the application object needs to update its state. */ void slotDataChanged(); void slotMoveToAccount(const QString& id); void slotUpdateMoveToAccountMenu(); /** * This slot collects information for a new scheduled transaction * based on transaction @a t and @a occurrence and saves it in the engine. */ void slotScheduleNew(const MyMoneyTransaction& t, eMyMoney::Schedule::Occurrence occurrence = eMyMoney::Schedule::Occurrence::Monthly); /** */ void slotScheduleDuplicate(); void slotAccountMapOnline(); void slotAccountUnmapOnline(); void slotAccountUpdateOnline(); void slotAccountUpdateOnlineAll(); /** * @brief Start dialog for an online banking transfer */ void slotNewOnlineTransfer(); /** * @brief Start dialog to edit onlineJob if possible * @param onlineJob id to edit */ void slotEditOnlineJob(const QString); /** * @brief Start dialog to edit onlineJob if possible */ void slotEditOnlineJob(const onlineJob); /** * @brief Start dialog to edit onlineJob if possible */ void slotEditOnlineJob(const onlineJobTyped); /** * @brief Saves an online banking job */ void slotOnlineJobSave(onlineJob job); /** * @brief Queue an online banking job */ void slotOnlineJobSend(onlineJob job); /** * @brief Send a list of onlineJobs */ void slotOnlineJobSend(QList jobs); /** * dummy method needed just for initialization */ void slotRemoveJob(); void slotEditJob(); /** * @brief Show the log currently selected online job */ void slotOnlineJobLog(); void slotOnlineJobLog(const QStringList& onlineJobIds); void slotManageGpgKeys(); void slotKeySelected(int idx); void slotStatusProgressDone(); public: /** * This method checks if there is at least one asset or liability account * in the current storage object. If not, it starts the new account wizard. */ void createInitialAccount(); /** * This method returns the last URL used or an empty URL * depending on the option setting if the last file should * be opened during startup or the open file dialog should * be displayed. * * @return URL of last opened file or empty if the program * should start with the open file dialog */ QUrl lastOpenedURL(); /** * construtor of KMyMoneyApp, calls all init functions to create the application. */ explicit KMyMoneyApp(QWidget* parent = 0); /** * Destructor */ ~KMyMoneyApp(); static void progressCallback(int current, int total, const QString&); void writeLastUsedDir(const QString& directory); QString readLastUsedDir() const; void writeLastUsedFile(const QString& fileName); QString readLastUsedFile() const; /** * Returns whether there is an importer available that can handle this file */ bool isImportableFile(const QUrl &url); /** * This method is used to update the caption of the application window. * It sets the caption to "filename [modified] - KMyMoney". * * @param skipActions if true, the actions will not be updated. This * is usually onyl required by some early calls when * these widgets are not yet created (the default is false). */ void updateCaption(bool skipActions = false); /** * This method returns a list of all 'other' dcop registered kmymoney processes. * It's a subset of the return of DCOPclient()->registeredApplications(). * * @retval QStringList of process ids */ QList instanceList() const; #ifdef KMM_DEBUG /** * Dump a list of the names of all defined KActions to stdout. */ void dumpActions() const; #endif /** * Popup the context menu with the respective @p containerName. * Valid container names are defined in kmymoneyui.rc */ void showContextMenu(const QString& containerName); /** * This method opens the category editor with the data found in @a account. The * parent account is preset to @a parent but can be modified. If the user * acknowledges, the category is created. */ void createCategory(MyMoneyAccount& account, const MyMoneyAccount& parent); /** * This method returns the account for a given @a key - @a value pair. * If the account is not found in the list of accounts, MyMoneyAccount() * is returned. The @a key - @a value pair can be in the account's kvp * container or the account's online settings kvp container. */ const MyMoneyAccount& account(const QString& key, const QString& value) const; /** * This method set the online parameters stored in @a kvps with the * account referenced by @a acc. */ void setAccountOnlineParameters(const MyMoneyAccount& acc, const MyMoneyKeyValueContainer& kvps); QUrl selectFile(const QString& title, const QString& path, const QString& mask, QFileDialog::FileMode, QWidget *widget); void createAccount(MyMoneyAccount& newAccount, MyMoneyAccount& parentAccount, MyMoneyAccount& brokerageAccount, MyMoneyMoney openingBal); QString filename() const; /** * Checks if the file with the @a url already exists. If so, * the user is asked if he/she wants to override the file. * If the user's answer is negative, @p false will be returned. * @p true will be returned in all other cases. */ bool okToWriteFile(const QUrl &url); /** * Return pointer to the WebConnect object */ WebConnect* webConnect() const; protected: /** save general Options like all bar positions and status as well as the geometry and the recent file list to the configuration * file */ void saveOptions(); /** * Creates the interfaces necessary for the plugins to work. Therefore, * this method must be called prior to loadPlugins(). */ void createInterfaces(); /** * load all available plugins. Make sure you have called createInterfaces() * before you call this one. */ void loadPlugins(); /** * unload all available plugins. Make sure you have called loadPlugins() * before you call this one. */ void unloadPlugins(); /** * @brief Checks if the given plugin is loaded on start up * * This filters plugins which are loaded on demand only and deactivated plugins. * The configGroup must point to the correct group already. */ bool isPluginEnabled(const KPluginMetaData& metaData, const KConfigGroup& configGroup); /** * read general options again and initialize all variables like the recent file list */ void readOptions(); /** initializes the KActions of the application */ void initActions(); /** initializes the dynamic menus (account selectors) */ void initDynamicMenus(); /** * sets up the statusbar for the main window by initialzing a statuslabel. */ void initStatusBar(); /** * @brief Establish connections between actions and views * * Must be called after creation of actions and views. */ void connectActionsAndViews(); /** queryClose is called by KMainWindow on each closeEvent of a window. Against the * default implementation (only returns true), this calls saveModified() on the document object to ask if the document shall * be saved if Modified; on cancel the closeEvent is rejected. * The settings are saved using saveOptions() if we are about to close. * @see KMainWindow#queryClose * @see QWidget#closeEvent */ virtual bool queryClose(); void slotCheckSchedules(); virtual void resizeEvent(QResizeEvent*); void createSchedule(MyMoneySchedule newSchedule, MyMoneyAccount& newAccount); /** * This method checks, if an account can be closed or not. An account * can be closed if: * * - the balance is zero and * - all children are already closed and * - there is no unfinished schedule referencing the account * * @param acc reference to MyMoneyAccount object in question * @retval true account can be closed * @retval false account cannot be closed */ KMyMoneyUtils::CanCloseAccountCodeE canCloseAccount(const MyMoneyAccount& acc) const; /** * This method checks if an account can be closed and enables/disables * the close account action * If disabled, it sets a tooltip explaning why it cannot be closed * @brief enableCloseAccountAction * @param acc reference to MyMoneyAccount object in question */ void enableCloseAccountAction(const MyMoneyAccount& acc); /** * Check if a list contains a payee with a given id * * @param list const reference to value list * @param id const reference to id * * @retval true object has been found * @retval false object is not in list */ bool payeeInList(const QList& list, const QString& id) const; /** * Check if a list contains a tag with a given id * * @param list const reference to value list * @param id const reference to id * * @retval true object has been found * @retval false object is not in list */ bool tagInList(const QList& list, const QString& id) const; /** * Mark the selected transactions as provided by @a flag. If * flag is @a MyMoneySplit::Unknown, the future state depends * on the current stat of the split's flag accoring to the * following table: * * - NotReconciled --> Cleared * - Cleared --> Reconciled * - Reconciled --> NotReconciled */ void markTransaction(eMyMoney::Split::State flag); /** * This method allows to skip the next scheduled transaction of * the given schedule @a s. * */ void skipSchedule(MyMoneySchedule& s); /** * This method allows to enter the next scheduled transaction of * the given schedule @a s. In case @a extendedKeys is @a true, * the given schedule can also be skipped or ignored. * If @a autoEnter is @a true and the schedule does not contain * an estimated value, the schedule is entered as is without further * interaction with the user. In all other cases, the user will * be presented a dialog and allowed to adjust the values for this * instance of the schedule. * * The transaction will be created and entered into the ledger * and the schedule updated. */ - KMyMoneyUtils::EnterScheduleResultCodeE enterSchedule(MyMoneySchedule& s, bool autoEnter = false, bool extendedKeys = false); + eDialogs::ScheduleResultCode enterSchedule(MyMoneySchedule& s, bool autoEnter = false, bool extendedKeys = false); /** * Creates a new institution entry in the MyMoneyFile engine * * @param institution MyMoneyInstitution object containing the data of * the institution to be created. */ void createInstitution(MyMoneyInstitution& institution); /** * This method unmatches the currently selected transactions */ void transactionUnmatch(); /** * This method matches the currently selected transactions */ void transactionMatch(); /** * This method preloads the holidays for the duration of the default forecast period */ void preloadHolidays(); public slots: void slotFileInfoDialog(); /** */ void slotFileNew(); /** open a file and load it into the document*/ void slotFileOpen(); /** opens a file from the recent files menu */ void slotFileOpenRecent(const QUrl &url); /** open a SQL database */ void slotOpenDatabase(); /** * saves the current document. If it has no name yet, the user * will be queried for it. * * @retval false save operation failed * @retval true save operation was successful */ bool slotFileSave(); /** * ask the user for the filename and save the current document * * @retval false save operation failed * @retval true save operation was successful */ bool slotFileSaveAs(); /** * ask the user to select a database and save the current document * * @retval false save operation failed * @retval true save operation was successful */ bool saveAsDatabase(); void slotSaveAsDatabase(); /** asks for saving if the file is modified, then closes the actual file and window */ void slotFileCloseWindow(); /** asks for saving if the file is modified, then closes the actual file */ void slotFileClose(); /** * closes all open windows by calling close() on each memberList item * until the list is empty, then quits the application. * If queryClose() returns false because the user canceled the * saveModified() dialog, the closing breaks. */ void slotFileQuit(); void slotFileConsistencyCheck(); /** * fires up the price table editor */ void slotPriceDialog(); /** * fires up the currency table editor */ void slotCurrencyDialog(); /** * dummy method needed just for initialization */ void slotShowTransactionDetail(); /** * Toggles the hide reconciled transactions setting */ void slotHideReconciledTransactions(); /** * Toggles the hide unused categories setting */ void slotHideUnusedCategories(); /** * Toggles the show all accounts setting */ void slotShowAllAccounts(); /** * changes the statusbar contents for the standard label permanently, * used to indicate current actions. Returns the previous value for * 'stacked' usage. * * @param text the text that is displayed in the statusbar */ QString slotStatusMsg(const QString &text); /** * This method changes the progress bar in the status line according * to the parameters @p current and @p total. The following special * cases exist: * * - current = -1 and total = -1 will reset the progress bar * - current = ?? and total != 0 will setup the 100% mark to @p total * - current = xx and total == 0 will set the percentage * * @param current the current value with respect to the initialised * 100% mark * @param total the total value (100%) */ void slotStatusProgressBar(int current, int total = 0); /** * Called to update stock and currency prices from the user menu */ void slotEquityPriceUpdate(); /** * Imports a KMM statement into the engine, triggering the appropriate * UI to handle account matching, payee creation, and someday * payee and transaction matching. */ bool slotStatementImport(const MyMoneyStatement& s, bool silent = false); /** * Essentially similar to the above slot, except this will load the file * from disk first, given the URL. */ bool slotStatementImport(const QString& url); /** * This slot starts the reconciliation of the currently selected account */ void slotAccountReconcileStart(); /** * This slot finishes a previously started reconciliation */ void slotAccountReconcileFinish(); /** * This slot postpones a previously started reconciliations */ void slotAccountReconcilePostpone(); /** * This slot deletes the currently selected account if possible */ void slotAccountDelete(); /** * This slot opens the account editor to edit the currently * selected account if possible */ void slotAccountEdit(); /** * This slot opens the selected account in the ledger view */ void slotAccountOpenEmpty(); void slotAccountOpen(const MyMoneyObject&); /** * Preloads the input dialog with the data of the current * selected institution and brings up the input dialog * and saves the information entered. */ void slotInstitutionEditEmpty(); void slotInstitutionEdit(const MyMoneyObject &obj); /** * Deletes the current selected institution. */ void slotInstitutionDelete(); /** * This slot closes the currently selected account if possible */ void slotAccountClose(); /** * This slot re-openes the currently selected account if possible */ void slotAccountReopen(); /** * This slot reparents account @p src to be a child of account @p dest * * @param src account to be reparented * @param dest new parent */ void slotReparentAccount(const MyMoneyAccount& src, const MyMoneyAccount& dest); /** * This slot reparents account @p src to be a held at institution @p dest * * @param src account to be reparented * @param dest new parent institution */ void slotReparentAccount(const MyMoneyAccount& src, const MyMoneyInstitution& dest); /** * This slot creates a transaction report for the selected account * and opens it in the reports view. */ void slotAccountTransactionReport(); /** * This slot opens the account options menu at the current cursor * position. */ void slotShowAccountContextMenu(const MyMoneyObject&); /** * This slot opens the schedule options menu at the current cursor * position. */ void slotShowScheduleContextMenu(); /** * This slot opens the institution options menu at the current cursor * position. */ void slotShowInstitutionContextMenu(const MyMoneyObject&); /** * This slot opens the investment options menu at the current cursor * position. */ void slotShowInvestmentContextMenu(); /** * This slot opens the payee options menu at the current cursor * position. */ void slotShowPayeeContextMenu(); /** * This slot opens the tag options menu at the current cursor * position. */ void slotShowTagContextMenu(); /** * This slot opens the budget options menu at the current cursor * position. */ void slotShowBudgetContextMenu(); /** * This slot opens the transaction options menu at the current cursor * position. */ void slotShowTransactionContextMenu(); /** * This slot opens the currency options menu at the current cursor * position. */ void slotShowCurrencyContextMenu(); /** * This slot opens the price options menu at the current cursor * position. */ void slotShowPriceContextMenu(); /** * Open onlineJob options menu at current cursor position. */ void slotShowOnlineJobContextMenu(); + /** + * Brings up the new category editor and saves the information. + */ + void slotCategoryNew(); + + /** + * Brings up the new category editor and saves the information. + * The dialog will be preset with the name and parent account. + * + * @param account reference of category to be created. The @p name member + * should be filled by the caller. The object will be filled + * with additional information during the creation process + * esp. the @p id member. + * @param parent reference to parent account (defaults to none) + */ + void slotCategoryNew(MyMoneyAccount& account, const MyMoneyAccount& parent); + void slotCategoryNew(MyMoneyAccount& account); + + /** + * Create a new investment + */ + void slotInvestmentNew(); + + /** + * Create a new investment in a given @p parent investment account + */ + void slotInvestmentNew(MyMoneyAccount& account, const MyMoneyAccount& parent); + + /** + * This slot opens the investment editor to edit the currently + * selected investment if possible + */ + void slotInvestmentEdit(); + + /** + * Deletes the current selected investment. + */ + void slotInvestmentDelete(); + + /** + */ + void slotPayeeNew(const QString& newnameBase, QString& id); + bool createPayeeNew(const QString& newnameBase, QString& id); + void slotPayeeNew(); + /** * This slot collects information for a new scheduled transaction * and saves it in the engine. @sa slotScheduleNew(const MyMoneyTransaction&) */ void slotScheduleNew(); /** * This slot allows to edit information the currently selected schedule */ void slotScheduleEdit(); /** * This slot allows to delete the currently selected schedule */ void slotScheduleDelete(); /** * This slot allows to enter the next scheduled transaction of * the currently selected schedule */ void slotScheduleEnter(); /** * This slot allows to skip the next scheduled transaction of * the currently selected schedule */ void slotScheduleSkip(); /** */ void slotTagNew(const QString& newnameBase, QString& id); void slotTagNew(); /** */ void slotTagDelete(); /** * This slot fires up the KCalc application */ void slotToolsStartKCalc(); void slotResetSelections(); void slotSelectAccount(const MyMoneyObject& account); void slotSelectInstitution(const MyMoneyObject& institution); void slotSelectInvestment(const MyMoneyObject& account); void slotSelectSchedule(); void slotSelectSchedule(const MyMoneySchedule& schedule); void slotSelectPayees(const QList& list); void slotSelectTags(const QList& list); void slotSelectBudget(const QList& list); void slotSelectTransactions(const KMyMoneyRegister::SelectedTransactions& list); void slotSelectCurrency(); void slotSelectCurrency(const MyMoneySecurity& currency); void slotSelectPrice(); void slotSelectPrice(const MyMoneyPrice& price); void slotTransactionMatch(); /** * Brings up the new account wizard and saves the information. */ void slotAccountNew(); void slotAccountNew(MyMoneyAccount&); - /** - * Brings up the new category editor and saves the information. - */ - void slotCategoryNew(); - - /** - * Brings up the new category editor and saves the information. - * The dialog will be preset with the name and parent account. - * - * @param account reference of category to be created. The @p name member - * should be filled by the caller. The object will be filled - * with additional information during the creation process - * esp. the @p id member. - * @param parent reference to parent account (defaults to none) - */ - void slotCategoryNew(MyMoneyAccount& account, const MyMoneyAccount& parent); - void slotCategoryNew(MyMoneyAccount& account); - /** * This method updates all KAction items to the current state. */ void slotUpdateActions(); /** * Brings up the input dialog and saves the information. */ void slotInstitutionNew(); /** * Brings up the input dialog and saves the information. If * the institution has been created, the @a id member is filled, * otherwise it is empty. * * @param institution reference to data to be used to create the * institution. id member will be updated. */ void slotInstitutionNew(MyMoneyInstitution& institution); /** * Loads a plugin */ void slotPluginLoad(const KPluginMetaData& metaData); /** * Unloads a plugin */ void slotPluginUnload(const KPluginMetaData& metaData); void webConnect(const QString& sourceUrl, const QByteArray &asn_id); void webConnect(const QUrl url) { webConnect(url.path(), QByteArray()); } private: /** * Create the transaction move menu and setup necessary connections. */ void createTransactionMoveMenu(); /** * This method sets the holidayRegion for use by the processing calendar. */ void setHolidayRegion(const QString& holidayRegion); /** * Load the status bar with the 'ready' message. This is hold in a single * place, so that is consistent with isReady(). */ void ready(); /** * Check if the status bar contains the 'ready' message. The return * value is used e.g. to detect if a quit operation is allowed or not. * * @retval true application is idle * @retval false application is active working on a longer operation */ bool isReady(); /** * Delete a possibly existing transaction editor but make sure to remove * any reference to it so that we avoid using a half-dead object */ void deleteTransactionEditor(); /** * delete all selected transactions w/o further questions */ void doDeleteTransactions(); /** * Re-implemented from IMyMoneyProcessingCalendar */ bool isProcessingDate(const QDate& date) const; /** * Depending on the setting of AutoSaveOnQuit, this method * asks the user to save the file or not. * * @returns see return values of KMessageBox::warningYesNoCancel() */ int askSaveOnClose(); /** * Implement common task when deleting or merging payees */ bool payeeReassign(int type); signals: /** * This signal is emitted when a new file is loaded. In the case file * is closed, this signal is also emitted with an empty url. */ void fileLoaded(const QUrl &url); /** * This signal is emitted when a payee/list of payees has been selected by * the GUI. If no payee is selected or the selection is removed, * @p payees is identical to an empty QList. This signal is used * by plugins to get information about changes. */ void payeesSelected(const QList& payees); /** * This signal is emitted when a tag/list of tags has been selected by * the GUI. If no tag is selected or the selection is removed, * @p tags is identical to an empty QList. This signal is used * by plugins to get information about changes. */ void tagsSelected(const QList& tags); /** * This signal is emitted when a transaction/list of transactions has been selected by * the GUI. If no transaction is selected or the selection is removed, * @p transactions is identical to an empty QList. This signal is used * by plugins to get information about changes. */ void transactionsSelected(const KMyMoneyRegister::SelectedTransactions& transactions); /** * This signal is sent out, when the user presses Ctrl+A or activates * the Select all transactions action. */ void selectAllTransactions(); /** * This signal is emitted when a list of budgets has been selected by * the GUI. If no budget is selected or the selection is removed, * @a budget is identical to an empty QList. This signal is used * by plugins to get information about changes. */ void budgetSelected(const QList& budget); void budgetRename(); /** * This signal is emitted when a new account has been selected by * the GUI. If no account is selected or the selection is removed, * @a account is identical to MyMoneyAccount(). This signal is used * by plugins to get information about changes. */ void accountSelected(const MyMoneyAccount& account); void investmentSelected(const MyMoneyAccount& account); /** * This signal is emitted when a new institution has been selected by * the GUI. If no institution is selected or the selection is removed, * @a institution is identical to MyMoneyInstitution(). This signal is used * by plugins to get information about changes. */ void institutionSelected(const MyMoneyInstitution& institution); /** * This signal is emitted when a new schedule has been selected by * the GUI. If no schedule is selected or the selection is removed, * @a schedule is identical to MyMoneySchedule(). This signal is used * by plugins to get information about changes. */ void scheduleSelected(const MyMoneySchedule& schedule); /** * This signal is emitted when a new currency has been selected by * the GUI. If no currency is selected or the selection is removed, * @a currency is identical to MyMoneySecurity(). This signal is used * by plugins to get information about changes. */ void currencySelected(const MyMoneySecurity& currency); /** * This signal is emitted when a new price has been selected by * the GUI. If no price is selected or the selection is removed, * @a price is identical to MyMoneyPrice(). */ void priceSelected(const MyMoneyPrice& price); void payeeRename(); void payeeCreated(const QString& id); void slotTagRename(); void tagCreated(const QString& id); void currencyRename(); void currencyCreated(const QString& id); void priceEdit(); void priceNew(); void priceDelete(); void priceOnlineUpdate(); void startMatchTransaction(const MyMoneyTransaction& t); void cancelMatchTransaction(); /** * This signal is emitted when an account has been successfully reconciled * and all transactions are updated in the engine. It can be used by plugins * to create reconciliation reports. * * @param account the account data * @param date the reconciliation date as provided through the dialog * @param startingBalance the starting balance as provided through the dialog * @param endingBalance the ending balance as provided through the dialog * @param transactionList reference to QList of QPair containing all * transaction/split pairs processed by the reconciliation. */ void accountReconciled(const MyMoneyAccount& account, const QDate& date, const MyMoneyMoney& startingBalance, const MyMoneyMoney& endingBalance, const QList >& transactionList); public: bool isActionToggled(const Action _a); static const QHash s_Actions; private: /// \internal d-pointer class. class Private; /* * Actually, one should write "Private * const d" but that confuses the KIDL * compiler in this context. It complains about the const keyword. So we leave * it out here */ /// \internal d-pointer instance. Private* d; }; extern KMyMoneyApp *kmymoney; typedef void(KMyMoneyApp::*KMyMoneyAppFunc)(); class KMStatus { public: KMStatus(const QString &text); ~KMStatus(); private: QString m_prevText; }; #define KMSTATUS(msg) KMStatus _thisStatus(msg) #endif // KMYMONEY_H diff --git a/kmymoney/kmymoneyutils.h b/kmymoney/kmymoneyutils.h index 8667dec06..138af45f7 100644 --- a/kmymoney/kmymoneyutils.h +++ b/kmymoney/kmymoneyutils.h @@ -1,392 +1,364 @@ /*************************************************************************** kmymoneyutils.h - description ------------------- begin : Wed Feb 5 2003 copyright : (C) 2000-2003 by Michael Edwardes email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #ifndef KMYMONEYUTILS_H #define KMYMONEYUTILS_H // ---------------------------------------------------------------------------- // QT Includes #include #include // ---------------------------------------------------------------------------- // KDE Headers // ---------------------------------------------------------------------------- // Project Includes #include "mymoneyenums.h" /** * @author Thomas Baumgart */ static QString m_lastNumberUsed; class QPixmap; class QWizard; class QWidget; class KGuiItem; class KXmlGuiWindow; class MyMoneyMoney; class MyMoneyAccount; class MyMoneySecurity; class MyMoneySchedule; class MyMoneySplit; class MyMoneyTransaction; class KMyMoneyUtils { public: - /** - * This enum is used to describe the bits of an account type filter mask. - * Each bit is used to define a specific account class. Multiple classes - * can be specified by OR'ing multiple entries. The special entry @p last - * marks the left most bit in the mask and is used by scanners of this - * bitmask to determine the end of processing. - */ - enum categoryTypeE { - none = 0x000, ///< no account class selected - liability = 0x001, ///< liability accounts selected - asset = 0x002, ///< asset accounts selected - expense = 0x004, ///< expense accounts selected - income = 0x008, ///< income accounts selected - equity = 0x010, ///< equity accounts selected - checking = 0x020, ///< checking accounts selected - savings = 0x040, ///< savings accounts selected - investment = 0x080, ///< investment accounts selected - creditCard = 0x100, ///< credit card accounts selected - last = 0x200 ///< the leftmost bit in the mask - }; - enum transactionTypeE { /** * Unknown transaction type (e.g. used for a transaction with only * a single split) */ Unknown, /** * A 'normal' transaction is one that consists out two splits: one * referencing an income/expense account, the other referencing * an asset/liability account. */ Normal, /** * A transfer denotes a transaction consisting of two splits. * Both of the splits reference an asset/liability * account. */ Transfer, /** * Whenever a transaction consists of more than 2 splits, * it is treated as 'split transaction'. */ SplitTransaction, /** * This transaction denotes a specific transaction where * a loan account is involved. Usually, a special dialog * is used to modify this transaction. */ LoanPayment, /** * This transaction denotes a specific transaction where * an investment is involved. Usually, a special dialog * is used to modify this transaction. */ InvestmentTransaction }; - enum EnterScheduleResultCodeE { - Cancel = 0, // cancel the operation - Enter, // enter the schedule - Skip, // skip the schedule - Ignore // ignore the schedule - }; - enum CanCloseAccountCodeE { AccountCanClose = 0, // can close the account AccountBalanceNonZero, // balance is non zero AccountChildrenOpen, // account has open children account AccountScheduleReference // account is referenced in a schedule }; static const int maxHomePageItems = 5; KMyMoneyUtils(); ~KMyMoneyUtils(); /** * This method is used to convert the occurrence type from its * internal representation into a human readable format. * * @param occurrence numerical representation of the MyMoneySchedule * occurrence type * * @return QString representing the human readable format translated according to the language cataglogue * * @sa MyMoneySchedule::occurrenceToString() * * @deprecated Use i18n(MyMoneySchedule::occurrenceToString(occurrence)) instead */ static const QString occurrenceToString(const eMyMoney::Schedule::Occurrence occurrence); /** * This method is used to convert the payment type from its * internal representation into a human readable format. * * @param paymentType numerical representation of the MyMoneySchedule * payment type * * @return QString representing the human readable format translated according to the language cataglogue * * @sa MyMoneySchedule::paymentMethodToString() */ static const QString paymentMethodToString(eMyMoney::Schedule::PaymentType paymentType); /** * This method is used to convert the schedule weekend option from its * internal representation into a human readable format. * * @param weekendOption numerical representation of the MyMoneySchedule * weekend option * * @return QString representing the human readable format translated according to the language cataglogue * * @sa MyMoneySchedule::weekendOptionToString() */ static const QString weekendOptionToString(eMyMoney::Schedule::WeekendOption weekendOption); /** * This method is used to convert the schedule type from its * internal representation into a human readable format. * * @param type numerical representation of the MyMoneySchedule * schedule type * * @return QString representing the human readable format translated according to the language cataglogue * * @sa MyMoneySchedule::scheduleTypeToString() */ static const QString scheduleTypeToString(eMyMoney::Schedule::Type type); /** * This method is used to convert a numeric index of an item * represented on the home page into its string form. * * @param idx numeric index of item * * @return QString with text of this item */ static const QString homePageItemToString(const int idx); /** * This method is used to convert the name of a home page item * to its internal numerical representation * * @param txt QString reference of the items name * * @retval 0 @p txt is unknown * @retval >0 numeric value for @p txt */ static int stringToHomePageItem(const QString& txt); /** * Retrieve a KDE KGuiItem for the new schedule button. * * @return The KGuiItem that can be used to display the icon and text */ static KGuiItem scheduleNewGuiItem(); /** * Retrieve a KDE KGuiItem for the account filter button * * @return The KGuiItem that can be used to display the icon and text */ static KGuiItem accountsFilterGuiItem(); /** * This method adds the file extension passed as argument @p extension * to the end of the file name passed as argument @p name if it is not present. * If @p name contains an extension it will be removed. * * @param name filename to be checked * @param extension extension to be added (w/o the dot) * * @retval true if @p name was changed * @retval false if @p name remained unchanged */ static bool appendCorrectFileExt(QString& name, const QString& extension); /** * Check that internal MyMoney engine constants use the same * values as the KDE constants. */ static void checkConstants(); static QString variableCSS(); /** * This method searches a KDE specific resource and applies country and * language settings during the search. Therefore, the parameter @p filename must contain * the characters '%1' which gets replaced with the language/country values. * * The search is performed in the following order (stopped immediately if a file was found): * - @c \%1 is replaced with _\.\ * - @c \%1 is replaced with _\ * - @c \%1 is replaced with _\ * - @c \%1 is replaced with the empty string * * @c \ and @c \ denote the respective KDE settings. * * Example: The KDE settings for country is Spain (es) and language is set * to Galician (gl). The code for looking up a file looks like this: * * @code * * : * QString fname = KMyMoneyUtils::findResource("appdata", "html/home%1.html") * : * * @endcode * * The method calls KStandardDirs::findResource() with the following values for the * parameter @p filename: * * - html/home_es.gl.html * - html/home_gl.html * - html/home_es.html * - html/home.html * * @note See KStandardDirs::findResource() for details on the parameters */ static QString findResource(QStandardPaths::StandardLocation type, const QString& filename); /** * This method returns the split referencing a stock account if * one exists in the transaction passed as @p t. If none is present * in @p t, an empty MyMoneySplit() object will be returned. * * @param t transaction to be checked for a stock account * @return MyMoneySplit object referencing a stock account or an * empty MyMoneySplit object. */ static const MyMoneySplit stockSplit(const MyMoneyTransaction& t); /** * This method analyses the splits of a transaction and returns * the type of transaction. Possible values are defined by the * KMyMoneyUtils::transactionTypeE enum. * * @param t const reference to the transaction * * @return KMyMoneyUtils::transactionTypeE value of the action */ static transactionTypeE transactionType(const MyMoneyTransaction& t); /** * This method modifies a scheduled loan transaction such that all * references to automatic calculated values are resolved to actual values. * * @param schedule const reference to the schedule the transaction is based on * @param transaction reference to the transaction to be checked and modified * @param balances QMap of (account-id,balance) pairs to be used as current balance * for the calculation of interest. If map is empty, the engine * will be interrogated for current balances. */ static void calculateAutoLoan(const MyMoneySchedule& schedule, MyMoneyTransaction& transaction, const QMap& balances); /** * Return next check number for account @a acc. */ static QString nextCheckNumber(const MyMoneyAccount& acc); static void updateLastNumberUsed(const MyMoneyAccount& acc, const QString& number); static void setLastNumberUsed(const QString& num); static QString lastNumberUsed(); /** * Returns previous number if offset is -1 or * the following number if offset is 1. */ static QString getAdjacentNumber(const QString& number, int offset = 1); /** * remove any non-numeric characters from check number * to allow validity check */ static quint64 numericPart(const QString & num); /** * Returns the text representing the reconcile flag. If @a text is @p true * then the full text will be returned otherwise a short form (usually one character). */ static QString reconcileStateToString(eMyMoney::Split::State flag, bool text = false); /** * Returns the transaction for @a schedule. In case of a loan payment the * transaction will be modified by calculateAutoLoan(). * The ID of the transaction as well as the entryDate will be reset. * * @returns adjusted transaction */ static MyMoneyTransaction scheduledTransaction(const MyMoneySchedule& schedule); /** * This method replaces the deprecated QApplication::mainWidget() from Qt 3.x. * It assumes that there is only one KXmlGuiWindow in the application, and * returns it. * * @return the first KXmlGuiWindow found in QApplication::topLevelWidgets() */ static KXmlGuiWindow* mainWindow(); /** * This method sets the button text and icons to the KDE standard ones * for the QWizard passed as argument. */ static void updateWizardButtons(QWizard *); /** * This method overlays an icon over another one, to get a composite one * eg. an icon to add accounts */ static QPixmap overlayIcon(const QString &iconName, const QString &overlayName, const Qt::Corner corner = Qt::BottomRightCorner, const int size = 64); static void dissectTransaction(const MyMoneyTransaction& transaction, const MyMoneySplit& split, MyMoneySplit& assetAccountSplit, QList& feeSplits, QList& interestSplits, MyMoneySecurity& security, MyMoneySecurity& currency, eMyMoney::Split::InvestmentTransactionType& transactionType); /** * This method deletes security and associated price list but asks beforehand. */ static void deleteSecurity(const MyMoneySecurity &security, QWidget *parent = nullptr); }; #endif diff --git a/kmymoney/plugins/ofximport/dialogs/kofxdirectconnectdlg.cpp b/kmymoney/plugins/ofximport/dialogs/kofxdirectconnectdlg.cpp index a7238df0c..25380d80e 100644 --- a/kmymoney/plugins/ofximport/dialogs/kofxdirectconnectdlg.cpp +++ b/kmymoney/plugins/ofximport/dialogs/kofxdirectconnectdlg.cpp @@ -1,226 +1,225 @@ /*************************************************************************** kofxdirectconnectdlg.cpp ------------------- begin : Sat Nov 13 2004 copyright : (C) 2002 by Ace Jones email : acejones@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "kofxdirectconnectdlg.h" #include "kmymoneysettings.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include -#include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include #include #include // ---------------------------------------------------------------------------- // Project Includes #include "mymoneyofxconnector.h" class KOfxDirectConnectDlg::Private { public: Private() : m_firstData(true) {} QFile m_fpTrace; bool m_firstData; }; KOfxDirectConnectDlg::KOfxDirectConnectDlg(const MyMoneyAccount& account, QWidget *parent) : KOfxDirectConnectDlgDecl(parent), d(new Private), m_tmpfile(0), m_connector(account), m_job(0) { } KOfxDirectConnectDlg::~KOfxDirectConnectDlg() { if (d->m_fpTrace.isOpen()) { d->m_fpTrace.close(); } delete m_tmpfile; delete d; } bool KOfxDirectConnectDlg::init() { show(); QByteArray request = m_connector.statementRequest(); if (request.isEmpty()) { hide(); return false; } // For debugging, dump out the request #if 0 QFile g("request.ofx"); g.open(QIODevice::WriteOnly); QTextStream(&g) << m_connector.url() << "\n" << QString(request); g.close(); #endif if (KMyMoneySettings::logOfxTransactions()) { QString logPath = KMyMoneySettings::logPath(); d->m_fpTrace.setFileName(QString("%1/ofxlog.txt").arg(logPath)); d->m_fpTrace.open(QIODevice::WriteOnly | QIODevice::Append); } if (d->m_fpTrace.isOpen()) { QByteArray data = m_connector.url().toUtf8(); d->m_fpTrace.write("url: ", 5); d->m_fpTrace.write(data, strlen(data)); d->m_fpTrace.write("\n", 1); d->m_fpTrace.write("request:\n", 9); QByteArray trcData(request); // make local copy trcData.replace('\r', ""); d->m_fpTrace.write(trcData, trcData.size()); d->m_fpTrace.write("\n", 1); d->m_fpTrace.write("response:\n", 10); } qDebug("creating job"); m_job = KIO::http_post(QUrl(m_connector.url()), request, KIO::HideProgressInfo); // open the temp file. We come around here twice if init() is called twice if (m_tmpfile) { qDebug() << "Already connected, using " << m_tmpfile->fileName(); delete m_tmpfile; //delete otherwise we mem leak } m_tmpfile = new QTemporaryFile(); // for debugging purposes one might want to leave the temp file around // in order to achieve this, please uncomment the next line // m_tmpfile->setAutoRemove(false); if (!m_tmpfile->open()) { qWarning("Unable to open tempfile '%s' for download.", qPrintable(m_tmpfile->fileName())); return false; } m_job->addMetaData("content-type", "Content-type: application/x-ofx"); connect(m_job, SIGNAL(result(KJob*)), this, SLOT(slotOfxFinished(KJob*))); connect(m_job, SIGNAL(data(KIO::Job*,QByteArray)), this, SLOT(slotOfxData(KIO::Job*,QByteArray))); setStatus(QString("Contacting %1...").arg(m_connector.url())); kProgress1->setMaximum(3); kProgress1->setValue(1); return true; } void KOfxDirectConnectDlg::setStatus(const QString& _status) { textLabel1->setText(_status); qDebug() << "STATUS:" << _status; } void KOfxDirectConnectDlg::setDetails(const QString& _details) { qDebug() << "DETAILS: " << _details; } void KOfxDirectConnectDlg::slotOfxData(KIO::Job*, const QByteArray& _ba) { qDebug("Got %d bytes of data", _ba.size()); if (d->m_firstData) { setStatus("Connection established, retrieving data..."); setDetails(QString("Downloading data to %1...").arg(m_tmpfile->fileName())); kProgress1->setValue(kProgress1->value() + 1); d->m_firstData = false; } m_tmpfile->write(_ba); setDetails(QString("Got %1 bytes").arg(_ba.size())); if (d->m_fpTrace.isOpen()) { QByteArray trcData(_ba); trcData.replace('\r', ""); d->m_fpTrace.write(trcData, trcData.size()); } } void KOfxDirectConnectDlg::slotOfxFinished(KJob* /* e */) { qDebug("Job finished"); kProgress1->setValue(kProgress1->value() + 1); setStatus("Completed."); if (d->m_fpTrace.isOpen()) { d->m_fpTrace.write("\nCompleted\n\n\n\n", 14); } int error = m_job->error(); if (m_tmpfile) { qDebug("Closing tempfile"); m_tmpfile->close(); } qDebug("Tempfile closed"); if (error) { qDebug("Show error message"); m_job->uiDelegate()->showErrorMessage(); } else if (m_job->isErrorPage()) { qDebug("Process error page"); QString details; if (m_tmpfile) { QFile f(m_tmpfile->fileName()); if (f.open(QIODevice::ReadOnly)) { QTextStream stream(&f); QString line; while (!stream.atEnd()) { details += stream.readLine(); // line of text excluding '\n' } f.close(); qDebug() << "The HTTP request failed: " << details; } } KMessageBox::detailedSorry(this, i18n("The HTTP request failed."), details, i18nc("The HTTP request failed", "Failed")); } else if (m_tmpfile) { qDebug("Emit statementReady signal with '%s'", qPrintable(m_tmpfile->fileName())); emit statementReady(m_tmpfile->fileName()); qDebug("Return from signal statementReady() processing"); } delete m_tmpfile; m_tmpfile = 0; hide(); qDebug("Finishing slotOfxFinished"); } void KOfxDirectConnectDlg::reject() { if (m_job) m_job->kill(); if (m_tmpfile) { m_tmpfile->close(); delete m_tmpfile; m_tmpfile = 0; } QDialog::reject(); } diff --git a/kmymoney/views/splitdialog.cpp b/kmymoney/views/splitdialog.cpp index c779a7bdc..cb6c8bbeb 100644 --- a/kmymoney/views/splitdialog.cpp +++ b/kmymoney/views/splitdialog.cpp @@ -1,372 +1,371 @@ /*************************************************************************** splitdialog.cpp ------------------- begin : Sun Apr 3 2016 copyright : (C) 2015 by Thomas Baumgart email : Thomas Baumgart ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "splitdialog.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes #include "ui_splitdialog.h" #include "mymoneyaccount.h" -#include "ledgermodel.h" #include "splitdelegate.h" #include "newtransactioneditor.h" #include "splitadjustdialog.h" #include "modelenums.h" #include "icons/icons.h" using namespace Icons; class SplitDialog::Private { public: Private(SplitDialog* p) : parent(p) , ui(new Ui_SplitDialog) { } void deleteSplits(QModelIndexList indexList); SplitDialog* parent; Ui_SplitDialog* ui; SplitDelegate* splitDelegate; /** * The account in which this split editor was opened */ MyMoneyAccount account; /** * The parent transaction editor which opened the split editor */ NewTransactionEditor* transactionEditor; MyMoneyMoney transactionTotal; MyMoneyMoney splitsTotal; }; static const int SumRow = 0; static const int DiffRow = 1; static const int AmountRow = 2; static const int HeaderCol = 0; static const int ValueCol = 1; void SplitDialog::Private::deleteSplits(QModelIndexList indexList) { if (indexList.isEmpty()) { return; } // remove from the end so that the row information stays // consistent and is not changed due to index changes QMap sortedList; foreach(auto index, indexList) { sortedList[index.row()] = index.row(); } QMap::const_iterator it = sortedList.constEnd(); do { --it; ui->splitView->model()->removeRow(*it); } while(it != sortedList.constBegin()); } SplitDialog::SplitDialog(const MyMoneyAccount& account, const MyMoneyMoney& amount, NewTransactionEditor* parent, Qt::WindowFlags f) : QDialog(parent, f) , d(new Private(this)) { d->transactionEditor = parent; d->account = account; d->transactionTotal = amount; d->ui->setupUi(this); d->ui->splitView->setColumnHidden((int)eLedgerModel::Column::Date, true); d->ui->splitView->setColumnHidden((int)eLedgerModel::Column::Number, true); d->ui->splitView->setColumnHidden((int)eLedgerModel::Column::Security, true); d->ui->splitView->setColumnHidden((int)eLedgerModel::Column::Reconciliation, true); d->ui->splitView->setColumnHidden((int)eLedgerModel::Column::Payment, false); d->ui->splitView->setColumnHidden((int)eLedgerModel::Column::Deposit, false); d->ui->splitView->setColumnHidden((int)eLedgerModel::Column::Quantity, true); d->ui->splitView->setColumnHidden((int)eLedgerModel::Column::Price, true); d->ui->splitView->setColumnHidden((int)eLedgerModel::Column::Amount, true); d->ui->splitView->setColumnHidden((int)eLedgerModel::Column::Value, true); d->ui->splitView->setColumnHidden((int)eLedgerModel::Column::Balance, true); d->ui->splitView->setSelectionMode(QAbstractItemView::ExtendedSelection); d->ui->splitView->setSelectionBehavior(QAbstractItemView::SelectRows); // setup the item delegate d->splitDelegate = new SplitDelegate(d->ui->splitView); d->ui->splitView->setItemDelegate(d->splitDelegate); d->ui->okButton->setIcon(QIcon::fromTheme(g_Icons[Icon::DialogOK])); d->ui->cancelButton->setIcon(QIcon::fromTheme(g_Icons[Icon::DialogCancel])); // setup some connections connect(d->ui->splitView, SIGNAL(aboutToStartEdit()), this, SLOT(disableButtons())); connect(d->ui->splitView, SIGNAL(aboutToFinishEdit()), this, SLOT(enableButtons())); connect(d->ui->deleteAllButton, SIGNAL(pressed()), this, SLOT(deleteAllSplits())); connect(d->ui->deleteButton, SIGNAL(pressed()), this, SLOT(deleteSelectedSplits())); connect(d->ui->deleteZeroButton, SIGNAL(pressed()), this, SLOT(deleteZeroSplits())); connect(d->ui->mergeButton, SIGNAL(pressed()), this, SLOT(mergeSplits())); connect(d->ui->newSplitButton, SIGNAL(pressed()), this, SLOT(newSplit())); // finish polishing the widgets QMetaObject::invokeMethod(this, "adjustSummary", Qt::QueuedConnection); } SplitDialog::~SplitDialog() { } int SplitDialog::exec() { if(!d->ui->splitView->model()) { qWarning() << "SplitDialog::exec() executed without a model. Use setModel() before calling exec()."; return QDialog::Rejected; } return QDialog::exec(); } void SplitDialog::accept() { adjustSummary(); bool accept = true; if(d->transactionTotal != d->splitsTotal) { QPointer dlg = new SplitAdjustDialog(this); dlg->setValues(d->ui->summaryView->item(AmountRow, ValueCol)->data(Qt::DisplayRole).toString(), d->ui->summaryView->item(SumRow, ValueCol)->data(Qt::DisplayRole).toString(), d->ui->summaryView->item(DiffRow, ValueCol)->data(Qt::DisplayRole).toString(), d->ui->splitView->model()->rowCount()); accept = false; if(dlg->exec() == QDialog::Accepted && dlg) { switch(dlg->selectedOption()) { case SplitAdjustDialog::SplitAdjustContinue: break; case SplitAdjustDialog::SplitAdjustChange: d->transactionTotal = d->splitsTotal; accept = true; break; case SplitAdjustDialog::SplitAdjustDistribute: qWarning() << "SplitDialog::accept needs to implement the case SplitAdjustDialog::SplitAdjustDistribute"; accept = true; break; case SplitAdjustDialog::SplitAdjustLeaveAsIs: accept = true; break; } } delete dlg; updateButtonState(); } if(accept) QDialog::accept(); } void SplitDialog::enableButtons() { d->ui->buttonContainer->setEnabled(true); } void SplitDialog::disableButtons() { d->ui->buttonContainer->setEnabled(false); } void SplitDialog::setModel(QAbstractItemModel* model) { d->ui->splitView->setModel(model); if(model->rowCount() > 0) { QModelIndex index = model->index(0, 0); d->ui->splitView->setCurrentIndex(index); } adjustSummary(); // force an update of the summary if data changes in the model connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), this, SLOT(adjustSummary())); connect(d->ui->splitView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)), this, SLOT(selectionChanged())); } void SplitDialog::adjustSummary() { d->splitsTotal = 0; for(int row = 0; row < d->ui->splitView->model()->rowCount(); ++row) { QModelIndex index = d->ui->splitView->model()->index(row, 0); if(index.isValid()) { d->splitsTotal += d->ui->splitView->model()->data(index, (int)eLedgerModel::Role::SplitValue).value(); } } QString formattedValue = d->splitsTotal.formatMoney(d->account.fraction()); d->ui->summaryView->item(SumRow, ValueCol)->setData(Qt::DisplayRole, formattedValue); if(d->transactionEditor) { d->transactionTotal = d->transactionEditor->transactionAmount(); formattedValue = d->transactionTotal.formatMoney(d->account.fraction()); d->ui->summaryView->item(AmountRow, ValueCol)->setData(Qt::DisplayRole, formattedValue); if((d->transactionTotal - d->splitsTotal).isNegative()) { d->ui->summaryView->item(DiffRow, HeaderCol)->setData(Qt::DisplayRole, i18nc("Split editor summary", "Assigned too much")); } else { d->ui->summaryView->item(DiffRow, HeaderCol)->setData(Qt::DisplayRole, i18nc("Split editor summary", "Unassigned")); } formattedValue = (d->transactionTotal - d->splitsTotal).abs().formatMoney(d->account.fraction()); d->ui->summaryView->item(DiffRow, ValueCol)->setData(Qt::DisplayRole, formattedValue); } else { d->ui->summaryView->item(SumRow, ValueCol)->setData(Qt::DisplayRole, QString()); d->ui->summaryView->item(AmountRow, ValueCol)->setData(Qt::DisplayRole, QString()); } adjustSummaryWidth(); updateButtonState(); } void SplitDialog::resizeEvent(QResizeEvent* ev) { QDialog::resizeEvent(ev); adjustSummaryWidth(); } void SplitDialog::adjustSummaryWidth() { d->ui->summaryView->resizeColumnToContents(1); d->ui->summaryView->horizontalHeader()->resizeSection(0, d->ui->summaryView->width() - d->ui->summaryView->horizontalHeader()->sectionSize(1) - 10); } void SplitDialog::newSplit() { // creating a new split is easy, because we simply // need to select the last entry in the view. If we // are on this row already with the editor closed things // are a bit more complicated. QModelIndex index = d->ui->splitView->currentIndex(); if(index.isValid()) { int row = index.row(); if(row != d->ui->splitView->model()->rowCount()-1) { d->ui->splitView->selectRow(d->ui->splitView->model()->rowCount()-1); } else { d->ui->splitView->edit(index); } } else { d->ui->splitView->selectRow(d->ui->splitView->model()->rowCount()-1); } } MyMoneyMoney SplitDialog::transactionAmount() const { return d->transactionTotal; } void SplitDialog::selectionChanged() { updateButtonState(); } void SplitDialog::updateButtonState() { d->ui->deleteButton->setEnabled(false); d->ui->deleteAllButton->setEnabled(false); d->ui->mergeButton->setEnabled(false); d->ui->deleteZeroButton->setEnabled(false); if(d->ui->splitView->selectionModel()->selectedRows().count() >= 1) { d->ui->deleteButton->setEnabled(true); } if(d->ui->splitView->model()->rowCount() > 2) { d->ui->deleteAllButton->setEnabled(true); } QAbstractItemModel* model = d->ui->splitView->model(); QSet accountIDs; for(int row = 0; row < model->rowCount(); ++row) { const QModelIndex index = model->index(row,0); // don't check the empty line at the end if(model->data(index, (int)eLedgerModel::Role::SplitId).toString().isEmpty()) continue; const QString accountID = model->data(index, (int)eLedgerModel::Role::AccountId).toString(); const MyMoneyMoney value = model->data(index, (int)eLedgerModel::Role::SplitShares).value(); if(accountIDs.contains(accountID)) { d->ui->mergeButton->setEnabled(true); } if(value.isZero()) { d->ui->deleteZeroButton->setEnabled(true); } } } void SplitDialog::deleteSelectedSplits() { d->deleteSplits(d->ui->splitView->selectionModel()->selectedRows()); adjustSummary(); } void SplitDialog::deleteAllSplits() { QAbstractItemModel* model = d->ui->splitView->model(); QModelIndexList list = model->match(model->index(0,0), (int)eLedgerModel::Role::SplitId, QLatin1String(".+"), -1, Qt::MatchRegExp ); d->deleteSplits(list); adjustSummary(); } void SplitDialog::deleteZeroSplits() { QAbstractItemModel* model = d->ui->splitView->model(); QModelIndexList list = model->match(model->index(0,0), (int)eLedgerModel::Role::SplitId, QLatin1String(".+"), -1, Qt::MatchRegExp ); for(int idx = 0; idx < list.count();) { QModelIndex index = list.at(idx); if(!model->data(index, (int)eLedgerModel::Role::SplitShares).value().isZero()) { list.removeAt(idx); } else { ++idx; } } d->deleteSplits(list); adjustSummary(); } void SplitDialog::mergeSplits() { qDebug() << "Merge splits not yet implemented."; adjustSummary(); } diff --git a/kmymoney/widgets/kmymoneyaccountselector.cpp b/kmymoney/widgets/kmymoneyaccountselector.cpp index 0af87ff68..bbb792146 100644 --- a/kmymoney/widgets/kmymoneyaccountselector.cpp +++ b/kmymoney/widgets/kmymoneyaccountselector.cpp @@ -1,486 +1,487 @@ /*************************************************************************** kmymoneyaccountselector.cpp - description ------------------- begin : Thu Sep 18 2003 copyright : (C) 2003 by Thomas Baumgart email : mte@users.sourceforge.net Javier Campos Morales Felix Rodriguez John C Thomas Baumgart Kevin Tambascio ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "kmymoneyaccountselector.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes #include "mymoneyfile.h" #include "mymoneyaccount.h" #include "kmymoneyutils.h" #include "kmymoneyglobalsettings.h" #include "icons/icons.h" #include "mymoneyenums.h" +#include "dialogenums.h" using namespace Icons; using namespace eMyMoney; kMyMoneyAccountSelector::kMyMoneyAccountSelector(QWidget *parent, Qt::WindowFlags flags, const bool createButtons) : KMyMoneySelector(parent, flags), m_allAccountsButton(0), m_noAccountButton(0), m_incomeCategoriesButton(0), m_expenseCategoriesButton(0) { if (createButtons) { QVBoxLayout* buttonLayout = new QVBoxLayout(); buttonLayout->setSpacing(6); m_allAccountsButton = new QPushButton(this); m_allAccountsButton->setObjectName("m_allAccountsButton"); m_allAccountsButton->setText(i18nc("Select all accounts", "All")); buttonLayout->addWidget(m_allAccountsButton); m_incomeCategoriesButton = new QPushButton(this); m_incomeCategoriesButton->setObjectName("m_incomeCategoriesButton"); m_incomeCategoriesButton->setText(i18n("Income")); buttonLayout->addWidget(m_incomeCategoriesButton); m_expenseCategoriesButton = new QPushButton(this); m_expenseCategoriesButton->setObjectName("m_expenseCategoriesButton"); m_expenseCategoriesButton->setText(i18n("Expense")); buttonLayout->addWidget(m_expenseCategoriesButton); m_noAccountButton = new QPushButton(this); m_noAccountButton->setObjectName("m_noAccountButton"); m_noAccountButton->setText(i18nc("No account", "None")); buttonLayout->addWidget(m_noAccountButton); QSpacerItem* spacer = new QSpacerItem(0, 67, QSizePolicy::Minimum, QSizePolicy::Expanding); buttonLayout->addItem(spacer); m_layout->addLayout(buttonLayout); connect(m_allAccountsButton, SIGNAL(clicked()), this, SLOT(slotSelectAllAccounts())); connect(m_noAccountButton, SIGNAL(clicked()), this, SLOT(slotDeselectAllAccounts())); connect(m_incomeCategoriesButton, SIGNAL(clicked()), this, SLOT(slotSelectIncomeCategories())); connect(m_expenseCategoriesButton, SIGNAL(clicked()), this, SLOT(slotSelectExpenseCategories())); } } kMyMoneyAccountSelector::~kMyMoneyAccountSelector() { } void kMyMoneyAccountSelector::removeButtons() { delete m_allAccountsButton; delete m_incomeCategoriesButton; delete m_expenseCategoriesButton; delete m_noAccountButton; } void kMyMoneyAccountSelector::selectCategories(const bool income, const bool expense) { QTreeWidgetItemIterator it_v(m_treeWidget); for (; *it_v != 0; ++it_v) { if ((*it_v)->text(0) == i18n("Income categories")) selectAllSubItems(*it_v, income); else if ((*it_v)->text(0) == i18n("Expense categories")) selectAllSubItems(*it_v, expense); } emit stateChanged(); } void kMyMoneyAccountSelector::setSelectionMode(QTreeWidget::SelectionMode mode) { m_incomeCategoriesButton->setHidden(mode == QTreeWidget::MultiSelection); m_expenseCategoriesButton->setHidden(mode == QTreeWidget::MultiSelection); KMyMoneySelector::setSelectionMode(mode); } QStringList kMyMoneyAccountSelector::accountList(const QList& filterList) const { QStringList list; QTreeWidgetItemIterator it(m_treeWidget, QTreeWidgetItemIterator::Selectable); while (*it) { QVariant id = (*it)->data(0, KMyMoneySelector::IdRole); MyMoneyAccount acc = MyMoneyFile::instance()->account(id.toString()); if (filterList.count() == 0 || filterList.contains(acc.accountType())) list << id.toString(); it++; } return list; } bool kMyMoneyAccountSelector::match(const QRegExp& exp, QTreeWidgetItem* item) const { if (!item->flags().testFlag(Qt::ItemIsSelectable)) return false; return exp.indexIn(item->data(0, KMyMoneySelector::KeyRole).toString().mid(1)) != -1; } bool kMyMoneyAccountSelector::contains(const QString& txt) const { QTreeWidgetItemIterator it(m_treeWidget, QTreeWidgetItemIterator::Selectable); QTreeWidgetItem* it_v; QString baseName = i18n("Asset") + '|' + i18n("Liability") + '|' + i18n("Income") + '|' + i18n("Expense") + '|' + i18n("Equity") + '|' + i18n("Security"); while ((it_v = *it) != 0) { QRegExp exp(QString("^(?:%1):%2$").arg(baseName).arg(QRegExp::escape(txt))); if (exp.indexIn(it_v->data(0, KMyMoneySelector::KeyRole).toString().mid(1)) != -1) { return true; } it++; } return false; } AccountSet::AccountSet() : m_count(0), m_file(MyMoneyFile::instance()), m_favorites(0), m_hideClosedAccounts(true) { } void AccountSet::addAccountGroup(Account group) { if (group == Account::Asset) { m_typeList << Account::Checkings; m_typeList << Account::Savings; m_typeList << Account::Cash; m_typeList << Account::AssetLoan; m_typeList << Account::CertificateDep; m_typeList << Account::Investment; m_typeList << Account::Stock; m_typeList << Account::MoneyMarket; m_typeList << Account::Asset; m_typeList << Account::Currency; } else if (group == Account::Liability) { m_typeList << Account::CreditCard; m_typeList << Account::Loan; m_typeList << Account::Liability; } else if (group == Account::Income) { m_typeList << Account::Income; } else if (group == Account::Expense) { m_typeList << Account::Expense; } else if (group == Account::Equity) { m_typeList << Account::Equity; } } void AccountSet::addAccountType(Account type) { m_typeList << type; } void AccountSet::removeAccountType(Account type) { int index = m_typeList.indexOf(type); if (index != -1) { m_typeList.removeAt(index); } } void AccountSet::clear() { m_typeList.clear(); } int AccountSet::load(kMyMoneyAccountSelector* selector) { QStringList list; QStringList::ConstIterator it_l; int count = 0; int typeMask = 0; QString currentId; if (selector->selectionMode() == QTreeWidget::SingleSelection) { QStringList list; selector->selectedItems(list); if (!list.isEmpty()) currentId = list.first(); } if (m_typeList.contains(Account::Checkings) || m_typeList.contains(Account::Savings) || m_typeList.contains(Account::Cash) || m_typeList.contains(Account::AssetLoan) || m_typeList.contains(Account::CertificateDep) || m_typeList.contains(Account::Investment) || m_typeList.contains(Account::Stock) || m_typeList.contains(Account::MoneyMarket) || m_typeList.contains(Account::Asset) || m_typeList.contains(Account::Currency)) - typeMask |= KMyMoneyUtils::asset; + typeMask |= eDialogs::Category::asset; if (m_typeList.contains(Account::CreditCard) || m_typeList.contains(Account::Loan) || m_typeList.contains(Account::Liability)) - typeMask |= KMyMoneyUtils::liability; + typeMask |= eDialogs::Category::liability; if (m_typeList.contains(Account::Income)) - typeMask |= KMyMoneyUtils::income; + typeMask |= eDialogs::Category::income; if (m_typeList.contains(Account::Expense)) - typeMask |= KMyMoneyUtils::expense; + typeMask |= eDialogs::Category::expense; if (m_typeList.contains(Account::Equity)) - typeMask |= KMyMoneyUtils::equity; + typeMask |= eDialogs::Category::equity; selector->clear(); QTreeWidget* lv = selector->listView(); m_count = 0; QString key; QTreeWidgetItem* after = 0; // create the favorite section first and sort it to the beginning key = QString("A%1").arg(i18n("Favorites")); m_favorites = selector->newItem(i18n("Favorites"), key); //get the account icon from cache or insert it if it is not there QPixmap accountPixmap; if (!QPixmapCache::find("account", accountPixmap)) { QIcon icon = QIcon::fromTheme(g_Icons[Icon::ViewBankAccount]); if (!icon.availableSizes().isEmpty()) accountPixmap = icon.pixmap(icon.availableSizes().first()); QPixmapCache::insert("account", accountPixmap); } m_favorites->setIcon(0, QIcon(accountPixmap)); - for (int mask = 0x01; mask != KMyMoneyUtils::last; mask <<= 1) { + for (auto mask = 0x01; mask != eDialogs::Category::last; mask <<= 1) { QTreeWidgetItem* item = 0; - if ((typeMask & mask & KMyMoneyUtils::asset) != 0) { + if ((typeMask & mask & eDialogs::Category::asset) != 0) { ++m_count; key = QString("B%1").arg(i18n("Asset")); item = selector->newItem(i18n("Asset accounts"), key); item->setIcon(0, m_file->asset().accountPixmap()); list = m_file->asset().accountList(); } - if ((typeMask & mask & KMyMoneyUtils::liability) != 0) { + if ((typeMask & mask & eDialogs::Category::liability) != 0) { ++m_count; key = QString("C%1").arg(i18n("Liability")); item = selector->newItem(i18n("Liability accounts"), key); item->setIcon(0, m_file->liability().accountPixmap()); list = m_file->liability().accountList(); } - if ((typeMask & mask & KMyMoneyUtils::income) != 0) { + if ((typeMask & mask & eDialogs::Category::income) != 0) { ++m_count; key = QString("D%1").arg(i18n("Income")); item = selector->newItem(i18n("Income categories"), key); item->setIcon(0, m_file->income().accountPixmap()); list = m_file->income().accountList(); if (selector->selectionMode() == QTreeWidget::MultiSelection) { selector->m_incomeCategoriesButton->show(); } } - if ((typeMask & mask & KMyMoneyUtils::expense) != 0) { + if ((typeMask & mask & eDialogs::Category::expense) != 0) { ++m_count; key = QString("E%1").arg(i18n("Expense")); item = selector->newItem(i18n("Expense categories"), key); item->setIcon(0, m_file->expense().accountPixmap()); list = m_file->expense().accountList(); if (selector->selectionMode() == QTreeWidget::MultiSelection) { selector->m_expenseCategoriesButton->show(); } } - if ((typeMask & mask & KMyMoneyUtils::equity) != 0) { + if ((typeMask & mask & eDialogs::Category::equity) != 0) { ++m_count; key = QString("F%1").arg(i18n("Equity")); item = selector->newItem(i18n("Equity accounts"), key); item->setIcon(0, m_file->equity().accountPixmap()); list = m_file->equity().accountList(); } if (!after) after = item; if (item != 0) { // scan all matching accounts found in the engine for (it_l = list.constBegin(); it_l != list.constEnd(); ++it_l) { const MyMoneyAccount& acc = m_file->account(*it_l); ++m_count; ++count; //this will include an account if it matches the account type and //if it is still open or it has been set to show closed accounts if (includeAccount(acc) && (!isHidingClosedAccounts() || !acc.isClosed())) { QString tmpKey; tmpKey = key + MyMoneyFile::AccountSeperator + acc.name(); QTreeWidgetItem* subItem = selector->newItem(item, acc.name(), tmpKey, acc.id()); subItem->setIcon(0, acc.accountPixmap()); if (acc.value("PreferredAccount") == "Yes" && m_typeList.contains(acc.accountType())) { selector->newItem(m_favorites, acc.name(), tmpKey, acc.id())->setIcon(0, acc.accountPixmap());; } if (acc.accountList().count() > 0) { subItem->setExpanded(true); count += loadSubAccounts(selector, subItem, tmpKey, acc.accountList()); } // the item is not selectable if it has been added only because a subaccount matches the type if (!m_typeList.contains(acc.accountType())) { selector->setSelectable(subItem, false); } subItem->sortChildren(1, Qt::AscendingOrder); } } item->sortChildren(1, Qt::AscendingOrder); } } m_favorites->sortChildren(1, Qt::AscendingOrder); lv->invisibleRootItem()->sortChildren(1, Qt::AscendingOrder); // if we don't have a favorite account or the selector is for multi-mode // we get rid of the favorite entry and subentries. if (m_favorites->childCount() == 0 || selector->selectionMode() == QTreeWidget::MultiSelection) { delete m_favorites; m_favorites = 0; } if (lv->itemAt(0, 0)) { if (currentId.isEmpty()) { lv->setCurrentItem(lv->itemAt(0, 0)); lv->clearSelection(); } else { selector->setSelected(currentId); } } selector->update(); return count; } int AccountSet::load(kMyMoneyAccountSelector* selector, const QString& baseName, const QList& accountIdList, const bool clear) { int count = 0; QTreeWidgetItem* item = 0; m_typeList.clear(); if (clear) { m_count = 0; selector->clear(); } item = selector->newItem(baseName); ++m_count; QList::ConstIterator it; for (it = accountIdList.constBegin(); it != accountIdList.constEnd(); ++it) { const MyMoneyAccount& acc = m_file->account(*it); if (acc.isClosed()) continue; QString tmpKey; // the first character must be preset. Since we don't know any sort order here, we just use A tmpKey = QString("A%1%2%3").arg(baseName, MyMoneyFile::AccountSeperator, acc.name()); selector->newItem(item, acc.name(), tmpKey, acc.id())->setIcon(0, acc.accountPixmap()); ++m_count; ++count; } QTreeWidget* lv = selector->listView(); if (lv->itemAt(0, 0)) { lv->setCurrentItem(lv->itemAt(0, 0)); lv->clearSelection(); } selector->update(); return count; } int AccountSet::loadSubAccounts(kMyMoneyAccountSelector* selector, QTreeWidgetItem* parent, const QString& key, const QStringList& list) { QStringList::ConstIterator it_l; int count = 0; for (it_l = list.constBegin(); it_l != list.constEnd(); ++it_l) { const MyMoneyAccount& acc = m_file->account(*it_l); // don't include stock accounts if not in expert mode if (acc.isInvest() && !KMyMoneyGlobalSettings::expertMode()) continue; //this will include an account if it matches the account type and //if it is still open or it has been set to show closed accounts if (includeAccount(acc) && (!isHidingClosedAccounts() || !acc.isClosed())) { QString tmpKey; tmpKey = key + MyMoneyFile::AccountSeperator + acc.name(); ++count; ++m_count; QTreeWidgetItem* item = selector->newItem(parent, acc.name(), tmpKey, acc.id()); item->setIcon(0, acc.accountPixmap()); if (acc.value("PreferredAccount") == "Yes" && m_typeList.contains(acc.accountType())) { selector->newItem(m_favorites, acc.name(), tmpKey, acc.id())->setIcon(0, acc.accountPixmap()); } if (acc.accountList().count() > 0) { item->setExpanded(true); count += loadSubAccounts(selector, item, tmpKey, acc.accountList()); } // the item is not selectable if it has been added only because a subaccount matches the type if (!m_typeList.contains(acc.accountType())) { selector->setSelectable(item, false); } item->sortChildren(1, Qt::AscendingOrder); } } return count; } bool AccountSet::includeAccount(const MyMoneyAccount& acc) { if (m_typeList.contains(acc.accountType())) return true; QStringList accounts = acc.accountList(); if (accounts.size() > 0) { QStringList::ConstIterator it_acc; for (it_acc = accounts.constBegin(); it_acc != accounts.constEnd(); ++it_acc) { MyMoneyAccount account = m_file->account(*it_acc); if (includeAccount(account)) return true; } } return false; } diff --git a/kmymoney/widgets/registeritem.h b/kmymoney/widgets/registeritem.h index f53a3f629..adea42ccc 100644 --- a/kmymoney/widgets/registeritem.h +++ b/kmymoney/widgets/registeritem.h @@ -1,306 +1,306 @@ /*************************************************************************** registeritem.h - description ------------------- begin : Tue Jun 13 2006 copyright : (C) 2000-2006 by Thomas Baumgart email : Thomas Baumgart ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #ifndef REGISTERITEM_H #define REGISTERITEM_H // ---------------------------------------------------------------------------- // QT Includes #include #include #include // ---------------------------------------------------------------------------- // KDE Includes // ---------------------------------------------------------------------------- // Project Includes #include "mymoneyobject.h" #include "mymoneymoney.h" #include "mymoneyenums.h" class MyMoneyMoney; namespace KMyMoneyRegister { -typedef enum { + enum CashFlowDirection : int { Deposit = 0, //< transaction is deposit Payment, //< transaction is payment Unknown //< transaction cashflow is unknown -} CashFlowDirection; +}; -typedef enum { + enum Action : int { ActionNone = -1, ActionCheck = 0, /* these should be values which qt 3.3 never uses for QTab: * qt starts upwards from 0 */ ActionDeposit = 12201, ActionTransfer = 12202, ActionWithdrawal = 12203, ActionAtm, // insert new values above this line MaxAction -} Action; +}; /** * Used to filter items from the register. */ struct RegisterFilter { enum ItemState { Any, Imported, Matched, Erroneous, NotMarked, NotReconciled, Cleared }; RegisterFilter(const QString &t, ItemState s) : state(s), text(t) { } ItemState state; QString text; }; class Register; /** * @author Thomas Baumgart */ class RegisterItem { public: RegisterItem(); RegisterItem(Register* parent); virtual ~RegisterItem(); virtual const char* className() = 0; virtual bool isSelectable() const = 0; virtual bool isSelected() const { return false; } virtual void setSelected(bool /* selected*/) {} virtual bool canHaveFocus() const = 0; virtual bool hasFocus() const { return false; } virtual bool hasEditorOpen() const { return false; } virtual void setFocus(bool /*focus*/, bool updateLens = true) { Q_UNUSED(updateLens); } virtual bool isErroneous() const = 0; // helper functions used for sorting virtual QDate sortPostDate() const { return nullDate; } virtual int sortSamePostDate() const = 0; virtual QDate sortEntryDate() const { return nullDate; } virtual const QString& sortPayee() const { return nullString; } virtual MyMoneyMoney sortValue() const { return nullValue; } virtual QString sortNumber() const { return nullString; } virtual const QString& sortEntryOrder() const { return nullString; } virtual CashFlowDirection sortType() const { return Deposit; } virtual const QString& sortCategory() const { return nullString; } virtual eMyMoney::Split::State sortReconcileState() const { return eMyMoney::Split::State::MaxReconcileState; } virtual const QString sortSecurity() const { return nullString; } /** * This method sets the row offset of the item in the register * to row. * * @param row row offset * * @note The row offset is based on QTable rows, not register * items. */ virtual void setStartRow(int row) { m_startRow = row; } int startRow() const { return m_startRow; } virtual int rowHeightHint() const; /** * This method modifies the number of rows required to display this item * in a Register. * It calls Register::forceUpdateLists() when the number differs. */ virtual void setNumRowsRegister(int rows); /** * This method modifies the number of rows required to display this item * in a Form. */ virtual void setNumRowsForm(int rows) { m_rowsForm = rows; } /** * This method returns the number of rows required to display this item * in a Register */ virtual int numRowsRegister() const { return m_rowsRegister; } /** * This method returns the number of rows required to display this item * in a Form */ virtual int numRowsForm() const { return m_rowsForm; } virtual int numColsForm() const { return 1; } /** * This method sets up the register item to be shown in normal (@p alternate = @p false) * or alternate (@p alternate = @p true) background. * * @param alternate selects normal or alternate background */ virtual void setAlternate(bool alternate) { m_alternate = alternate; } virtual void paintRegisterCell(QPainter *painter, QStyleOptionViewItem &option, const QModelIndex &index) = 0; virtual void paintFormCell(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) = 0; virtual const QString& id() const { return MyMoneyObject::emptyId(); } /** * Sets the parent of this item to be the register @p parent * * @param parent pointer to register */ void setParent(Register* parent); /** * This member returns a pointer to the parent object * * @retval pointer to Register */ Register* parent() const { return m_parent; } void setNeedResize() { m_needResize = true; } bool isVisible() const { return m_visible; } /** * Marks the item visible depending on @a visible and * updates the underlying register object */ virtual void setVisible(bool visible); /** * Marks the item visible depending on @a visible but * does not update the underlying register object. Returns * true, if visibility has changed. */ virtual bool markVisible(bool visible); void setNextItem(RegisterItem* p) { m_next = p; } void setPrevItem(RegisterItem* p) { m_prev = p; } RegisterItem* nextItem() const { return m_next; } RegisterItem* prevItem() const { return m_prev; } virtual bool matches(const RegisterFilter&) const = 0; /** * Checks if the mouse hovered over an area that has a tooltip associated with it. * The mouse position is given in relative coordinates to the @a startRow and the * @a row and @a col of the item are also passed as relative values. * * If a tooltip shall be shown, this method presets the rectangle @a r with the * area in register coordinates and @a msg with the string that will be passed * to QToolTip::tip. @a true is returned in this case. * * If no tooltip is available, @a false will be returned. */ virtual bool maybeTip(const QPoint& /* relpos */, int /* row */, int /* col */, QRect& /* r */, QString& /* msg */) { return false; } protected: /// This method serves as helper for all constructors void init(); protected: Register* m_parent; RegisterItem* m_prev; RegisterItem* m_next; int m_startRow; int m_rowsRegister; int m_rowsForm; bool m_alternate; bool m_needResize; bool m_visible; private: static QDate nullDate; static QString nullString; static MyMoneyMoney nullValue; }; } // namespace #endif diff --git a/kmymoney/widgets/transaction.cpp b/kmymoney/widgets/transaction.cpp index a70a0fa17..664461028 100644 --- a/kmymoney/widgets/transaction.cpp +++ b/kmymoney/widgets/transaction.cpp @@ -1,2198 +1,2201 @@ /*************************************************************************** transaction.cpp - description ------------------- begin : Tue Jun 13 2006 copyright : (C) 2000-2006 by Thomas Baumgart (C) 2017 by Ł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. * * * ***************************************************************************/ #include "transaction.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include // ---------------------------------------------------------------------------- // Project Includes #include "mymoneyutils.h" #include "mymoneytransaction.h" #include "mymoneysplit.h" #include "mymoneyfile.h" #include "mymoneypayee.h" #include "mymoneytag.h" #include "register.h" #include "kmymoneycategory.h" #include "kmymoneydateinput.h" #include "transactionform.h" #include "kmymoneylineedit.h" #include "kmymoneyedit.h" #include "transactioneditor.h" #include "investtransactioneditor.h" #include "kmymoneyutils.h" #include "kmymoneymvccombo.h" +#ifndef KMM_DESIGNER +#include "stdtransactioneditor.h" +#endif #include "kmymoneyglobalsettings.h" using namespace KMyMoneyRegister; using namespace KMyMoneyTransactionForm; static unsigned char attentionSign[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x08, 0x06, 0x00, 0x00, 0x00, 0x8D, 0x89, 0x1D, 0x0D, 0x00, 0x00, 0x00, 0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7C, 0x08, 0x64, 0x88, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2E, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2E, 0x6F, 0x72, 0x67, 0x9B, 0xEE, 0x3C, 0x1A, 0x00, 0x00, 0x02, 0x05, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8D, 0xAD, 0x95, 0xBF, 0x4B, 0x5B, 0x51, 0x14, 0xC7, 0x3F, 0x2F, 0xBC, 0x97, 0x97, 0x97, 0x97, 0x77, 0xF3, 0xF2, 0x1C, 0xA4, 0x54, 0x6B, 0x70, 0x10, 0x44, 0x70, 0x2A, 0x91, 0x2E, 0x52, 0x02, 0x55, 0x8A, 0xB5, 0xA3, 0xAB, 0x38, 0x08, 0x66, 0xCC, 0xEE, 0xE0, 0xE2, 0x20, 0xB8, 0x38, 0xB8, 0xB8, 0xF8, 0x1F, 0x38, 0x29, 0xA5, 0x29, 0x74, 0x90, 0x0E, 0x0D, 0x0E, 0x22, 0x1D, 0x44, 0xA8, 0xD0, 0xD4, 0xB4, 0x58, 0x4B, 0x09, 0xF9, 0xF1, 0x4A, 0x3B, 0xD4, 0xD3, 0xE1, 0x55, 0xD3, 0x34, 0xAF, 0x49, 0x6C, 0x3D, 0xF0, 0x85, 0x7B, 0xCF, 0xFD, 0x9E, 0xEF, 0x3D, 0xE7, 0xFE, 0xD4, 0x44, 0x84, 0xDB, 0xB4, 0x48, 0x2F, 0xA4, 0x94, 0xAB, 0xE5, 0x52, 0xAE, 0x96, 0xEB, 0x49, 0x51, 0x44, 0x3A, 0x02, 0x18, 0x88, 0xC7, 0xF1, 0xE3, 0x71, 0x7C, 0x60, 0xA0, 0x1B, 0xBF, 0x6B, 0x86, 0x49, 0xC5, 0x46, 0x3E, 0x47, 0x34, 0x9F, 0x23, 0x9A, 0x54, 0x6C, 0xFC, 0x57, 0x86, 0x40, 0xC6, 0x4B, 0xE1, 0x37, 0xCA, 0x48, 0xA3, 0x8C, 0x78, 0x29, 0x7C, 0x20, 0xD3, 0x31, 0xA6, 0xD3, 0xA0, 0x52, 0x1C, 0x6D, 0x6F, 0x72, 0xD9, 0x28, 0x23, 0xFE, 0x07, 0x64, 0x7B, 0x93, 0x4B, 0xA5, 0x38, 0xFA, 0x27, 0x41, 0x60, 0x6E, 0x74, 0x84, 0x7A, 0xE5, 0x1D, 0x92, 0x54, 0x88, 0xE7, 0x22, 0xD5, 0x12, 0x32, 0x3A, 0x42, 0x1D, 0x98, 0xBB, 0x91, 0x20, 0x60, 0xDA, 0x36, 0x17, 0xFB, 0x7B, 0xC8, 0xC1, 0x4B, 0x04, 0x02, 0xBC, 0x7E, 0x81, 0xEC, 0xEF, 0x21, 0xB6, 0xCD, 0x05, 0x60, 0xF6, 0x2C, 0x68, 0x9A, 0x2C, 0xCF, 0x4C, 0xE1, 0x4B, 0x05, 0x39, 0x3F, 0x69, 0x0A, 0xBE, 0x7F, 0x83, 0x48, 0x05, 0x99, 0x99, 0xC2, 0x37, 0x4D, 0x96, 0x7B, 0x12, 0x04, 0xFA, 0x2D, 0x8B, 0xC6, 0xE9, 0x61, 0x10, 0x2C, 0x15, 0xC4, 0x8A, 0x21, 0x86, 0x8E, 0xFC, 0xF8, 0x12, 0xF4, 0x4F, 0x0F, 0x11, 0xCB, 0xA2, 0x01, 0xF4, 0x77, 0x3D, 0x36, 0x4E, 0x82, 0xF5, 0xA5, 0x05, 0x8C, 0xE1, 0x74, 0xD3, 0x37, 0x34, 0x18, 0x20, 0xF2, 0x8B, 0x3D, 0x9C, 0x86, 0xA5, 0x05, 0x0C, 0x27, 0xC1, 0x7A, 0xC7, 0x63, 0x03, 0x8C, 0x2B, 0x07, 0xBF, 0x5A, 0x6A, 0x66, 0x27, 0x15, 0x64, 0x3A, 0x8B, 0x3C, 0x7A, 0xD8, 0xEA, 0xAB, 0x96, 0x10, 0xE5, 0xE0, 0x03, 0xE3, 0x7F, 0xCD, 0x50, 0x39, 0x6C, 0xAD, 0xAD, 0x10, 0x53, 0xAA, 0x75, 0xD2, 0xF4, 0xBD, 0x00, 0x2D, 0x5C, 0x05, 0x6B, 0x2B, 0xC4, 0x94, 0xC3, 0xD6, 0xEF, 0xFE, 0x6B, 0x41, 0x4D, 0xD3, 0x66, 0xFB, 0x3C, 0xC6, 0x16, 0xE7, 0xDB, 0x97, 0x61, 0xE2, 0x3E, 0x3C, 0xC8, 0xB4, 0x15, 0xC7, 0xE2, 0x3C, 0x91, 0x3E, 0x8F, 0x31, 0x4D, 0xD3, 0x66, 0x5B, 0x4A, 0x06, 0x8C, 0x84, 0xCD, 0x59, 0x61, 0xA7, 0xB5, 0xAC, 0x2B, 0x9C, 0x1C, 0x04, 0x08, 0x1B, 0x2B, 0xEC, 0x20, 0x09, 0x9B, 0x33, 0xC0, 0xB8, 0xDE, 0x65, 0x43, 0x27, 0x9F, 0x9D, 0xA4, 0x1E, 0x16, 0xF0, 0xF9, 0x6D, 0xB0, 0xC3, 0x86, 0x1E, 0xB4, 0xC3, 0x38, 0xD9, 0x49, 0xEA, 0x86, 0x4E, 0xFE, 0xEA, 0x29, 0xF4, 0x2C, 0x8B, 0xDA, 0x71, 0x31, 0x9C, 0xFC, 0xF5, 0x23, 0x32, 0x34, 0x88, 0xDC, 0xBD, 0x13, 0x5C, 0xBF, 0x30, 0xCE, 0x71, 0x11, 0xB1, 0x2C, 0x6A, 0x80, 0xA7, 0xDB, 0x36, 0xAB, 0x4F, 0xA6, 0x89, 0xBA, 0x49, 0x38, 0xFF, 0xD4, 0xBE, 0x4E, 0x00, 0xAF, 0x9E, 0x81, 0x08, 0xD4, 0xEA, 0x01, 0xFE, 0x34, 0x37, 0x09, 0x4F, 0x1F, 0x13, 0xDD, 0x7D, 0xCE, 0xAA, 0x96, 0x72, 0x29, 0x7C, 0xFB, 0xCE, 0x44, 0xB8, 0xD4, 0xCD, 0x2C, 0x66, 0x52, 0xD4, 0x6E, 0xFB, 0x0B, 0xF8, 0x09, 0x63, 0x63, 0x31, 0xE4, 0x85, 0x76, 0x2E, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; Transaction::Transaction(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId) : RegisterItem(parent), m_transaction(transaction), m_split(split), m_form(0), m_uniqueId(m_transaction.id()), m_formRowHeight(-1), m_selected(false), m_focus(false), m_erroneous(false), m_inEdit(false), m_inRegisterEdit(false), m_showBalance(true), m_reducedIntensity(false) { MyMoneyFile* file = MyMoneyFile::instance(); // load the account if (!m_split.accountId().isEmpty()) m_account = file->account(m_split.accountId()); // load the payee if (!m_split.payeeId().isEmpty()) { m_payee = file->payee(m_split.payeeId()).name(); } if (parent->account().isIncomeExpense()) { m_payeeHeader = m_split.shares().isNegative() ? i18n("From") : i18n("Pay to"); } else { m_payeeHeader = m_split.shares().isNegative() ? i18n("Pay to") : i18n("From"); } // load the tag if (!m_split.tagIdList().isEmpty()) { const QList t = m_split.tagIdList(); for (int i = 0; i < t.count(); i++) { m_tagList << file->tag(t[i]).name(); m_tagColorList << file->tag(t[i]).tagColor(); } } // load the currency if (!m_transaction.id().isEmpty()) m_splitCurrencyId = m_account.currencyId(); // check if transaction is erroneous or not m_erroneous = !m_transaction.splitSum().isZero(); if (!m_uniqueId.isEmpty()) { m_uniqueId += '-'; QString id; id.setNum(uniqueId); m_uniqueId += id.rightJustified(3, '0'); } } void Transaction::setFocus(bool focus, bool updateLens) { if (focus != m_focus) { m_focus = focus; } if (updateLens) { if (KMyMoneyGlobalSettings::ledgerLens() || !KMyMoneyGlobalSettings::transactionForm() || KMyMoneyGlobalSettings::showRegisterDetailed() || m_parent->m_ledgerLensForced) { if (focus) setNumRowsRegister(numRowsRegister(true)); else setNumRowsRegister(numRowsRegister(KMyMoneyGlobalSettings::showRegisterDetailed())); } } } bool Transaction::paintRegisterCellSetup(QPainter *painter, QStyleOptionViewItem &option, const QModelIndex &index) { Q_UNUSED(painter) if (m_reducedIntensity) { option.palette.setColor(QPalette::Text, option.palette.color(QPalette::Disabled, QPalette::Text)); } if (m_selected) { option.state |= QStyle::State_Selected; } else { option.state &= ~QStyle::State_Selected; } if (m_focus) { option.state |= QStyle::State_HasFocus; } else { option.state &= ~QStyle::State_HasFocus; } if (option.widget && option.widget->hasFocus()) { option.palette.setCurrentColorGroup(QPalette::Active); } else { option.palette.setCurrentColorGroup(QPalette::Inactive); } if (index.column() == 0) { option.viewItemPosition = QStyleOptionViewItem::Beginning; } else if (index.column() == MaxColumns - 1) { option.viewItemPosition = QStyleOptionViewItem::End; } else { option.viewItemPosition = QStyleOptionViewItem::Middle; } // do we need to switch to the error color? if (m_erroneous) { option.palette.setColor(QPalette::Text, KMyMoneyGlobalSettings::schemeColor(SchemeColor::TransactionErroneous)); } // do we need to switch to the negative balance color? if (index.column() == BalanceColumn) { bool showNegative = m_balance.isNegative(); if (m_account.accountGroup() == eMyMoney::Account::Liability && !m_balance.isZero()) showNegative = !showNegative; if (showNegative) option.palette.setColor(QPalette::Text, KMyMoneyGlobalSettings::schemeColor(SchemeColor::TransactionErroneous)); } return true; } void Transaction::registerCellText(QString& txt, int row, int col) { Qt::Alignment align; registerCellText(txt, align, row, col, 0); } void Transaction::paintRegisterCell(QPainter *painter, QStyleOptionViewItem &option, const QModelIndex &index) { painter->save(); if (paintRegisterCellSetup(painter, option, index)) { const QStyle *style = option.widget ? option.widget->style() : QApplication::style(); const QWidget* widget = option.widget; // clear the mouse over state before painting the background option.state &= ~QStyle::State_MouseOver; // the background if (option.state & QStyle::State_Selected || option.state & QStyle::State_HasFocus) { // if this is not the first row of the transaction paint the previous rows // since the selection background is painted from the first row of the transaction if (index.row() > startRow()) { QStyleOptionViewItem optionSibling = option; QModelIndex previousRowItem = index.sibling(index.row() - 1, index.column()); optionSibling.rect = m_parent->visualRect(previousRowItem); paintRegisterCell(painter, optionSibling, previousRowItem); } // paint the selection background only from the first row on to the last row at once if (index.row() == startRow()) { QRect old = option.rect; int extraHeight = 0; if (m_inRegisterEdit) { // since, when editing a transaction inside the register (without the transaction form), // row heights can have various sizes (the memo row is larger than the rest) we have // to iterate over all the items of the transaction to compute the size of the selection rectangle // of course we start with the item after this one because it's size is already in the rectangle for (int i = startRow() + 1; i < startRow() + numRowsRegister(); ++i) { extraHeight += m_parent->visualRect(index.sibling(i, index.column())).height(); } } else { // we are not editing in the register so all rows have the same sizes just compute the extra height extraHeight = (numRowsRegister() - 1) * option.rect.height(); } option.rect.setBottom(option.rect.bottom() + extraHeight); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, widget); if (m_focus && index.column() == DetailColumn) { option.state |= QStyle::State_HasFocus; style->drawPrimitive(QStyle::PE_FrameFocusRect, &option, painter, widget); } option.rect = old; } } else { if (m_alternate) { painter->fillRect(option.rect, option.palette.alternateBase()); } else { painter->fillRect(option.rect, option.palette.base()); } } // the text // construct the text for the cell QString txt; option.displayAlignment = Qt::AlignVCenter; if (m_transaction != MyMoneyTransaction() && !m_inRegisterEdit) { registerCellText(txt, option.displayAlignment, index.row() - startRow(), index.column(), painter); } if (Qt::mightBeRichText(txt)) { QTextDocument document; // this should set the alignment of the html but it does not work so htmls will be left aligned document.setDefaultTextOption(QTextOption(option.displayAlignment)); document.setDocumentMargin(2); document.setHtml(txt); painter->translate(option.rect.topLeft()); QAbstractTextDocumentLayout::PaintContext ctx; ctx.palette = option.palette; // Highlighting text if item is selected if (m_selected) ctx.palette.setColor(QPalette::Text, option.palette.color(QPalette::HighlightedText)); document.documentLayout()->draw(painter, ctx); painter->translate(-option.rect.topLeft()); } else { // draw plain text properly aligned style->drawItemText(painter, option.rect.adjusted(2, 0, -2, 0), option.displayAlignment, option.palette, true, txt, m_selected ? QPalette::HighlightedText : QPalette::Text); } // draw the grid if it's needed if (KMyMoneySettings::showGrid()) { const int gridHint = style->styleHint(QStyle::SH_Table_GridLineColor, &option, widget); const QPen gridPen = QPen(QColor(static_cast(gridHint)), 0); QPen old = painter->pen(); painter->setPen(gridPen); if (index.row() == startRow()) painter->drawLine(option.rect.topLeft(), option.rect.topRight()); painter->drawLine(option.rect.topLeft(), option.rect.bottomLeft()); painter->setPen(old); } // possible icons if (index.row() == startRow() && index.column() == DetailColumn) { if (m_erroneous) { QPixmap attention; attention.loadFromData(attentionSign, sizeof(attentionSign), 0, 0); style->drawItemPixmap(painter, option.rect, Qt::AlignRight | Qt::AlignVCenter, attention); } } } painter->restore(); } int Transaction::formRowHeight(int /*row*/) { if (m_formRowHeight < 0) { m_formRowHeight = formRowHeight(); } return m_formRowHeight; } int Transaction::formRowHeight() const { if (m_formRowHeight < 0) { // determine the height of the objects in the table kMyMoneyDateInput dateInput; KMyMoneyCategory category(0, true); return qMax(dateInput.sizeHint().height(), category.sizeHint().height()); } return m_formRowHeight; } void Transaction::setupForm(TransactionForm* form) { m_form = form; form->verticalHeader()->setUpdatesEnabled(false); form->horizontalHeader()->setUpdatesEnabled(false); form->setRowCount(numRowsForm()); form->setColumnCount(numColsForm()); // Force all cells to have some text (so that paintCell is called for each cell) for (int r = 0; r < numRowsForm(); ++r) { for (int c = 0; c < numColsForm(); ++c) { if (r == 0 && form->columnWidth(c) == 0) { form->setColumnWidth(c, 10); } } } form->horizontalHeader()->setUpdatesEnabled(true); form->verticalHeader()->setUpdatesEnabled(true); loadTab(form); } void Transaction::paintFormCell(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) { if (!m_form) return; QRect cellRect = option.rect; QRect textRect(cellRect); textRect.setWidth(textRect.width() - 2); textRect.setHeight(textRect.height() - 2); painter->setPen(option.palette.text().color()); QString txt; Qt::Alignment align = Qt::AlignVCenter; bool editField = formCellText(txt, align, index.row(), index.column(), painter); // if we have an editable field and don't currently edit the transaction // show the background in a different color if (editField && !m_inEdit) { painter->fillRect(textRect, option.palette.alternateBase()); } if (!m_inEdit) painter->drawText(textRect, align, txt); } void Transaction::setupPalette(const QPalette& palette, QMap& editWidgets) { QMap::iterator it_w; for (it_w = editWidgets.begin(); it_w != editWidgets.end(); ++it_w) { if (*it_w) { (*it_w)->setPalette(palette); } } } void Transaction::setupFormPalette(QMap& editWidgets) { QPalette palette = m_parent->palette(); palette.setColor(QPalette::Active, QPalette::Base, palette.color(QPalette::Active, QPalette::Base)); setupPalette(palette, editWidgets); } void Transaction::setupRegisterPalette(QMap& editWidgets) { // make sure, we're using the right palette QPalette palette = m_parent->palette(); // use the highlight color as background palette.setColor(QPalette::Active, QPalette::Background, palette.color(QPalette::Active, QPalette::Highlight)); setupPalette(palette, editWidgets); } QWidget* Transaction::focusWidget(QWidget* w) const { if (w) { while (w->focusProxy()) w = w->focusProxy(); } return w; } void Transaction::arrangeWidget(QTableWidget* tbl, int row, int col, QWidget* w) const { if (w) { tbl->setCellWidget(row, col, w); // remove the widget from the QTable's eventFilter so that all // events will be directed to the edit widget w->removeEventFilter(tbl); } } bool Transaction::haveNumberField() const { bool rc = true; switch (m_account.accountType()) { case eMyMoney::Account::Savings: case eMyMoney::Account::Cash: case eMyMoney::Account::Loan: case eMyMoney::Account::AssetLoan: case eMyMoney::Account::Asset: case eMyMoney::Account::Liability: case eMyMoney::Account::Equity: rc = KMyMoneyGlobalSettings::alwaysShowNrField(); break; case eMyMoney::Account::Checkings: case eMyMoney::Account::CreditCard: // the next case is used for the editor when the account // is unknown (eg. when creating new schedules) case eMyMoney::Account::Unknown: break; default: rc = false; break; } return rc; } bool Transaction::maybeTip(const QPoint& cpos, int row, int col, QRect& r, QString& msg) { if (col != DetailColumn) return false; if (!m_erroneous && m_transaction.splitCount() < 3) return false; // check for detail column in row 0 of the transaction for a possible // exclamation mark. m_startRow is based 0, whereas the row to obtain // the modelindex is based 1, so we need to add one here r = m_parent->visualRect(m_parent->model()->index(m_startRow + 1, col)); r.setBottom(r.bottom() + (numRowsRegister() - 1)*r.height()); if (r.contains(cpos) && m_erroneous) { if (m_transaction.splits().count() < 2) { msg = QString("%1").arg(i18n("Transaction is missing a category assignment.")); } else { const MyMoneySecurity& sec = MyMoneyFile::instance()->security(m_account.currencyId()); msg = QString("%1").arg(i18n("The transaction has a missing assignment of %1.", MyMoneyUtils::formatMoney(m_transaction.splitSum().abs(), m_account, sec))); } return true; } // check if the mouse cursor is located on row 1 of the transaction // and display the details of a split transaction if it is one if (row == 1 && r.contains(cpos) && m_transaction.splitCount() > 2) { MyMoneyFile* file = MyMoneyFile::instance(); QList::const_iterator it_s; QString txt; const MyMoneySecurity& sec = file->security(m_transaction.commodity()); MyMoneyMoney factor(1, 1); if (!m_split.value().isNegative()) factor = -factor; for (it_s = m_transaction.splits().constBegin(); it_s != m_transaction.splits().constEnd(); ++it_s) { if (*it_s == m_split) continue; const MyMoneyAccount& acc = file->account((*it_s).accountId()); QString category = file->accountToCategory(acc.id()); QString amount = MyMoneyUtils::formatMoney(((*it_s).value() * factor), acc, sec); txt += QString("%1%2").arg(category, amount); } msg = QString("%1
").arg(txt); return true; } return false; } QString Transaction::reconcileState(bool text) const { QString txt = KMyMoneyUtils::reconcileStateToString(m_split.reconcileFlag(), text); if ((text == true) && (txt == i18nc("Unknown reconciliation state", "Unknown")) && (m_transaction == MyMoneyTransaction())) txt.clear(); return txt; } void Transaction::startEditMode() { m_inEdit = true; // hide the original tabbar since the edit tabbar will be added KMyMoneyTransactionForm::TransactionForm* form = dynamic_cast(m_form); form->tabBar()->setVisible(false); // only update the number of lines displayed if we edit inside the register if (m_inRegisterEdit) setNumRowsRegister(numRowsRegister(true)); } void Transaction::leaveEditMode() { // show the original tabbar since the edit tabbar was removed KMyMoneyTransactionForm::TransactionForm* form = dynamic_cast(m_form); form->tabBar()->setVisible(true); // make sure we reset the row height of all the transaction's rows because it could have been changed during edit if (m_parent) { for (int i = 0; i < numRowsRegister(); ++i) m_parent->setRowHeight(m_startRow + i, m_parent->rowHeightHint()); } m_inEdit = false; m_inRegisterEdit = false; setFocus(hasFocus(), true); } void Transaction::singleLineMemo(QString& txt, const MyMoneySplit& split) const { txt = split.memo(); // remove empty lines txt.replace("\n\n", "\n"); // replace '\n' with ", " txt.replace('\n', ", "); } int Transaction::rowHeightHint() const { return m_inEdit ? formRowHeight() : RegisterItem::rowHeightHint(); } bool Transaction::matches(const RegisterFilter& filter) const { // check if the state matches if (!transaction().id().isEmpty()) { switch (filter.state) { default: break; case RegisterFilter::Imported: if (!transaction().isImported()) return false; break; case RegisterFilter::Matched: if (!split().isMatched()) return false; break; case RegisterFilter::Erroneous: if (transaction().splitSum().isZero()) return false; break; case RegisterFilter::NotMarked: if (split().reconcileFlag() != eMyMoney::Split::State::NotReconciled) return false; break; case RegisterFilter::NotReconciled: if (split().reconcileFlag() != eMyMoney::Split::State::NotReconciled && split().reconcileFlag() != eMyMoney::Split::State::Cleared) return false; break; case RegisterFilter::Cleared: if (split().reconcileFlag() != eMyMoney::Split::State::Cleared) return false; break; } } // check if the text matches if (filter.text.isEmpty() || m_transaction.splitCount() == 0) return true; MyMoneyFile* file = MyMoneyFile::instance(); const QList&list = m_transaction.splits(); QList::const_iterator it_s; for (it_s = list.begin(); it_s != list.end(); ++it_s) { // check if the text is contained in one of the fields // memo, number, payee, tag, account if ((*it_s).memo().contains(filter.text, Qt::CaseInsensitive) || (*it_s).number().contains(filter.text, Qt::CaseInsensitive)) return true; if (!(*it_s).payeeId().isEmpty()) { const MyMoneyPayee& payee = file->payee((*it_s).payeeId()); if (payee.name().contains(filter.text, Qt::CaseInsensitive)) return true; } if (!(*it_s).tagIdList().isEmpty()) { const QList& t = (*it_s).tagIdList(); for (int i = 0; i < t.count(); i++) { if ((file->tag(t[i])).name().contains(filter.text, Qt::CaseInsensitive)) return true; } } const MyMoneyAccount& acc = file->account((*it_s).accountId()); if (acc.name().contains(filter.text, Qt::CaseInsensitive)) return true; QString s(filter.text); s.replace(MyMoneyMoney::thousandSeparator(), QChar()); if (!s.isEmpty()) { // check if any of the value field matches if a value has been entered QString r = (*it_s).value().formatMoney(m_account.fraction(), false); if (r.contains(s, Qt::CaseInsensitive)) return true; const MyMoneyAccount& acc = file->account((*it_s).accountId()); r = (*it_s).shares().formatMoney(acc.fraction(), false); if (r.contains(s, Qt::CaseInsensitive)) return true; } } return false; } void Transaction::setShowBalance(bool showBalance) { m_showBalance = showBalance; } void Transaction::setVisible(bool visible) { if (visible != isVisible()) { RegisterItem::setVisible(visible); RegisterItem* p; Transaction* t; if (!visible) { // if we are hidden, we need to inform all previous transactions // about it so that they don't show the balance p = prevItem(); while (p) { t = dynamic_cast(p); if (t) { if (!t->m_showBalance) break; t->m_showBalance = false; } p = p->prevItem(); } } else { // if we are shown, we need to check if the next transaction // is visible and change the display of the balance p = this; do { p = p->nextItem(); t = dynamic_cast(p); } while (!t && p); // if the next transaction is visible or I am the last one if ((t && t->m_showBalance) || !t) { m_showBalance = true; p = prevItem(); while (p && p->isVisible()) { t = dynamic_cast(p); if (t) { if (t->m_showBalance) break; t->m_showBalance = true; } p = p->prevItem(); } } } } } void Transaction::setSelected(bool selected) { if (!selected || (selected && isVisible())) m_selected = selected; } StdTransaction::StdTransaction(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId) : Transaction(parent, transaction, split, uniqueId), m_showAccountRow(false) { try { m_categoryHeader = i18n("Category"); switch (transaction.splitCount()) { default: m_category = i18nc("Split transaction (category replacement)", "Split transaction"); break; case 0: // the empty transaction case 1: break; case 2: setupFormHeader(m_transaction.splitByAccount(m_split.accountId(), false).accountId()); break; } } catch (const MyMoneyException &e) { qDebug() << "Problem determining the category for transaction '" << m_transaction.id() << "'. Reason: " << e.what() << "\n"; } m_rowsForm = 6; if (KMyMoneyUtils::transactionType(m_transaction) == KMyMoneyUtils::InvestmentTransaction) { MyMoneySplit split = KMyMoneyUtils::stockSplit(m_transaction); m_payee = MyMoneyFile::instance()->account(split.accountId()).name(); QString addon; if (split.action() == MyMoneySplit::ActionBuyShares) { if (split.value().isNegative()) { addon = i18n("Sell"); } else { addon = i18n("Buy"); } } else if (split.action() == MyMoneySplit::ActionDividend) { addon = i18n("Dividend"); } else if (split.action() == MyMoneySplit::ActionYield) { addon = i18n("Yield"); } else if (split.action() == MyMoneySplit::ActionInterestIncome) { addon = i18n("Interest Income"); } if (!addon.isEmpty()) { m_payee += QString(" (%1)").arg(addon); } m_payeeHeader = i18n("Activity"); m_category = i18n("Investment transaction"); } // setup initial size setNumRowsRegister(numRowsRegister(KMyMoneyGlobalSettings::showRegisterDetailed())); emit parent->itemAdded(this); } void StdTransaction::setupFormHeader(const QString& id) { m_category = MyMoneyFile::instance()->accountToCategory(id); switch (MyMoneyFile::instance()->account(id).accountGroup()) { case eMyMoney::Account::Asset: case eMyMoney::Account::Liability: m_categoryHeader = m_split.shares().isNegative() ? i18n("Transfer to") : i18n("Transfer from"); break; default: m_categoryHeader = i18n("Category"); break; } } KMyMoneyRegister::Action StdTransaction::actionType() const { KMyMoneyRegister::Action action = ActionNone; // if at least one split is referencing an income or // expense account, we will not call it a transfer QList::const_iterator it_s; for (it_s = m_transaction.splits().begin(); it_s != m_transaction.splits().end(); ++it_s) { if ((*it_s).accountId() == m_split.accountId()) continue; MyMoneyAccount acc = MyMoneyFile::instance()->account((*it_s).accountId()); if (acc.accountGroup() == eMyMoney::Account::Income || acc.accountGroup() == eMyMoney::Account::Expense) { // otherwise, we have to determine between deposit and withdrawal action = m_split.shares().isNegative() ? ActionWithdrawal : ActionDeposit; break; } } // otherwise, it's a transfer if (it_s == m_transaction.splits().end()) action = ActionTransfer; return action; } void StdTransaction::loadTab(TransactionForm* form) { TabBar* bar = form->tabBar(); bar->setSignalEmission(TabBar::SignalNever); for (int i = 0; i < bar->count(); ++i) { bar->setTabEnabled(i, true); } if (m_transaction.splitCount() > 0) { bar->setCurrentIndex(actionType()); } bar->setSignalEmission(TabBar::SignalAlways); } void StdTransaction::setupForm(TransactionForm* form) { Transaction::setupForm(form); form->setSpan(4, ValueColumn1, 3, 1); } bool StdTransaction::showRowInForm(int row) const { return row == 0 ? m_showAccountRow : true; } void StdTransaction::setShowRowInForm(int row, bool show) { if (row == 0) m_showAccountRow = show; } bool StdTransaction::formCellText(QString& txt, Qt::Alignment& align, int row, int col, QPainter* /* painter */) { // if(m_transaction != MyMoneyTransaction()) { switch (row) { case 0: switch (col) { case LabelColumn1: align |= Qt::AlignLeft; txt = i18n("Account"); break; } break; case 1: switch (col) { case LabelColumn1: align |= Qt::AlignLeft; txt = m_payeeHeader; break; case ValueColumn1: align |= Qt::AlignLeft; txt = m_payee; break; case LabelColumn2: align |= Qt::AlignLeft; if (haveNumberField()) txt = i18n("Number"); break; case ValueColumn2: align |= Qt::AlignRight; if (haveNumberField()) txt = m_split.number(); break; } break; case 2: switch (col) { case LabelColumn1: align |= Qt::AlignLeft; txt = m_categoryHeader; break; case ValueColumn1: align |= Qt::AlignLeft; txt = m_category; if (m_transaction != MyMoneyTransaction()) { if (txt.isEmpty() && !m_split.value().isZero()) txt = i18n("*** UNASSIGNED ***"); } break; case LabelColumn2: align |= Qt::AlignLeft; txt = i18n("Date"); break; case ValueColumn2: align |= Qt::AlignRight; if (m_transaction != MyMoneyTransaction()) txt = QLocale().toString(m_transaction.postDate(), QLocale::ShortFormat); break; } break; case 3: switch (col) { case LabelColumn1: align |= Qt::AlignLeft; txt = i18n("Tags"); break; case ValueColumn1: align |= Qt::AlignLeft; if (!m_tagList.isEmpty()) { for (int i = 0; i < m_tagList.size() - 1; i++) txt += m_tagList[i] + ", "; txt += m_tagList.last(); } //if (m_transaction != MyMoneyTransaction()) // txt = m_split.tagId(); break; case LabelColumn2: align |= Qt::AlignLeft; txt = i18n("Amount"); break; case ValueColumn2: align |= Qt::AlignRight; if (m_transaction != MyMoneyTransaction()) { txt = (m_split.value(m_transaction.commodity(), m_splitCurrencyId).abs()).formatMoney(m_account.fraction()); } break; } break; case 4: switch (col) { case LabelColumn1: align |= Qt::AlignLeft; txt = i18n("Memo"); break; case ValueColumn1: align &= ~Qt::AlignVCenter; align |= Qt::AlignTop; align |= Qt::AlignLeft; if (m_transaction != MyMoneyTransaction()) txt = m_split.memo().section('\n', 0, 2); break; } break; case 5: switch (col) { case LabelColumn2: align |= Qt::AlignLeft; txt = i18n("Status"); break; case ValueColumn2: align |= Qt::AlignRight; txt = reconcileState(); break; } } // } if (col == ValueColumn2 && row == 1) { return haveNumberField(); } return (col == ValueColumn1 && row < 5) || (col == ValueColumn2 && row > 0 && row != 4); } void StdTransaction::registerCellText(QString& txt, Qt::Alignment& align, int row, int col, QPainter* painter) { switch (row) { case 0: switch (col) { case NumberColumn: align |= Qt::AlignLeft; if (haveNumberField()) txt = m_split.number(); break; case DateColumn: align |= Qt::AlignLeft; txt = QLocale().toString(m_transaction.postDate(), QLocale::ShortFormat); break; case DetailColumn: switch (m_parent->getDetailsColumnType()) { case PayeeFirst: txt = m_payee; break; case AccountFirst: txt = m_category; if (!m_tagList.isEmpty()) { txt += " ( "; for (int i = 0; i < m_tagList.size() - 1; i++) { txt += " " + m_tagList[i] + ", "; } txt += " " + m_tagList.last() + " )"; } break; } align |= Qt::AlignLeft; if (txt.isEmpty() && m_rowsRegister < 3) { singleLineMemo(txt, m_split); } if (txt.isEmpty() && m_rowsRegister < 2) { if (m_account.accountType() != eMyMoney::Account::Income && m_account.accountType() != eMyMoney::Account::Expense) { txt = m_category; if (txt.isEmpty() && !m_split.value().isZero()) { txt = i18n("*** UNASSIGNED ***"); if (painter) painter->setPen(KMyMoneyGlobalSettings::schemeColor(SchemeColor::TransactionErroneous)); } } } break; case ReconcileFlagColumn: align |= Qt::AlignHCenter; txt = reconcileState(false); break; case PaymentColumn: align |= Qt::AlignRight; if (m_split.value().isNegative()) { txt = (-m_split.value(m_transaction.commodity(), m_splitCurrencyId)).formatMoney(m_account.fraction()); } break; case DepositColumn: align |= Qt::AlignRight; if (!m_split.value().isNegative()) { txt = m_split.value(m_transaction.commodity(), m_splitCurrencyId).formatMoney(m_account.fraction()); } break; case BalanceColumn: align |= Qt::AlignRight; if (m_showBalance) txt = m_balance.formatMoney(m_account.fraction()); else txt = "----"; break; case AccountColumn: // txt = m_objects->account(m_transaction.splits()[0].accountId()).name(); txt = MyMoneyFile::instance()->account(m_split.accountId()).name(); break; default: break; } break; case 1: switch (col) { case DetailColumn: switch (m_parent->getDetailsColumnType()) { case PayeeFirst: txt = m_category; if (!m_tagList.isEmpty()) { txt += " ( "; for (int i = 0; i < m_tagList.size() - 1; i++) { txt += " " + m_tagList[i] + ", "; } txt += " " + m_tagList.last() + " )"; } break; case AccountFirst: txt = m_payee; break; } align |= Qt::AlignLeft; if (txt.isEmpty() && !m_split.value().isZero()) { txt = i18n("*** UNASSIGNED ***"); if (painter) painter->setPen(KMyMoneyGlobalSettings::schemeColor(SchemeColor::TransactionErroneous)); } break; default: break; } break; case 2: switch (col) { case DetailColumn: align |= Qt::AlignLeft; singleLineMemo(txt, m_split); break; default: break; } break; } } int StdTransaction::registerColWidth(int col, const QFontMetrics& cellFontMetrics) { QString txt; int firstRow = 0, lastRow = numRowsRegister(); int nw = 0; for (int i = firstRow; i <= lastRow; ++i) { Qt::Alignment align; registerCellText(txt, align, i, col, 0); int w = cellFontMetrics.width(txt + " "); if (w > nw) nw = w; } return nw; } void StdTransaction::arrangeWidgetsInForm(QMap& editWidgets) { if (!m_form || !m_parent) return; setupFormPalette(editWidgets); arrangeWidget(m_form, 0, LabelColumn1, editWidgets["account-label"]); arrangeWidget(m_form, 0, ValueColumn1, editWidgets["account"]); arrangeWidget(m_form, 1, LabelColumn1, editWidgets["cashflow"]); arrangeWidget(m_form, 1, ValueColumn1, editWidgets["payee"]); arrangeWidget(m_form, 2, LabelColumn1, editWidgets["category-label"]); arrangeWidget(m_form, 2, ValueColumn1, editWidgets["category"]->parentWidget()); arrangeWidget(m_form, 3, LabelColumn1, editWidgets["tag-label"]); arrangeWidget(m_form, 3, ValueColumn1, editWidgets["tag"]); arrangeWidget(m_form, 4, LabelColumn1, editWidgets["memo-label"]); arrangeWidget(m_form, 4, ValueColumn1, editWidgets["memo"]); if (haveNumberField()) { arrangeWidget(m_form, 1, LabelColumn2, editWidgets["number-label"]); arrangeWidget(m_form, 1, ValueColumn2, editWidgets["number"]); } arrangeWidget(m_form, 2, LabelColumn2, editWidgets["date-label"]); arrangeWidget(m_form, 2, ValueColumn2, editWidgets["postdate"]); arrangeWidget(m_form, 3, LabelColumn2, editWidgets["amount-label"]); arrangeWidget(m_form, 3, ValueColumn2, editWidgets["amount"]); arrangeWidget(m_form, 5, LabelColumn2, editWidgets["status-label"]); arrangeWidget(m_form, 5, ValueColumn2, editWidgets["status"]); // get rid of the hints. we don't need them for the form QMap::iterator it; for (it = editWidgets.begin(); it != editWidgets.end(); ++it) { KMyMoneyCombo* combo = dynamic_cast(*it); kMyMoneyLineEdit* edit = dynamic_cast(*it); KMyMoneyPayeeCombo* payee = dynamic_cast(*it); KTagContainer* tag = dynamic_cast(*it); if (combo) combo->setPlaceholderText(QString()); if (edit) edit->setPlaceholderText(QString()); if (payee) payee->setPlaceholderText(QString()); if (tag) tag->tagCombo()->setPlaceholderText(QString()); } KMyMoneyTransactionForm::TransactionForm* form = dynamic_cast(m_form); TabBar* w = dynamic_cast(editWidgets["tabbar"]); if (w) { // insert the tabbar in the boxlayout so it will take the place of the original tabbar which was hidden QBoxLayout* boxLayout = dynamic_cast(form->tabBar()->parentWidget()->layout()); boxLayout->insertWidget(0, w); } } void StdTransaction::tabOrderInForm(QWidgetList& tabOrderWidgets) const { QStringList taborder = KMyMoneyGlobalSettings::stdTransactionFormTabOrder().split(',', QString::SkipEmptyParts); QStringList::const_iterator it_s = taborder.constBegin(); QWidget* w; while (it_s != taborder.constEnd()) { if (*it_s == "account") { tabOrderWidgets.append(focusWidget(m_form->cellWidget(0, ValueColumn1))); } else if (*it_s == "cashflow") { tabOrderWidgets.append(focusWidget(m_form->cellWidget(1, LabelColumn1))); } else if (*it_s == "payee") { tabOrderWidgets.append(focusWidget(m_form->cellWidget(1, ValueColumn1))); } else if (*it_s == "category") { // make sure to have the category field and the split button as separate tab order widgets // ok, we have to have some internal knowledge about the KMyMoneyCategory object, but // it's one of our own widgets, so we actually don't care. Just make sure, that we don't // go haywire when someone changes the KMyMoneyCategory object ... QWidget* w = m_form->cellWidget(2, ValueColumn1); tabOrderWidgets.append(focusWidget(w)); w = w->findChild("splitButton"); if (w) tabOrderWidgets.append(w); } else if (*it_s == "tag") { tabOrderWidgets.append(focusWidget(m_form->cellWidget(3, ValueColumn1))); } else if (*it_s == "memo") { tabOrderWidgets.append(focusWidget(m_form->cellWidget(4, ValueColumn1))); } else if (*it_s == "number") { if (haveNumberField()) { if ((w = focusWidget(m_form->cellWidget(1, ValueColumn2)))) tabOrderWidgets.append(w); } } else if (*it_s == "date") { tabOrderWidgets.append(focusWidget(m_form->cellWidget(2, ValueColumn2))); } else if (*it_s == "amount") { tabOrderWidgets.append(focusWidget(m_form->cellWidget(3, ValueColumn2))); } else if (*it_s == "state") { tabOrderWidgets.append(focusWidget(m_form->cellWidget(5, ValueColumn2))); } ++it_s; } } void StdTransaction::arrangeWidgetsInRegister(QMap& editWidgets) { if (!m_parent) return; setupRegisterPalette(editWidgets); if (haveNumberField()) arrangeWidget(m_parent, m_startRow + 0, NumberColumn, editWidgets["number"]); arrangeWidget(m_parent, m_startRow + 0, DateColumn, editWidgets["postdate"]); arrangeWidget(m_parent, m_startRow + 1, DateColumn, editWidgets["status"]); arrangeWidget(m_parent, m_startRow + 0, DetailColumn, editWidgets["payee"]); arrangeWidget(m_parent, m_startRow + 1, DetailColumn, editWidgets["category"]->parentWidget()); arrangeWidget(m_parent, m_startRow + 2, DetailColumn, editWidgets["tag"]); arrangeWidget(m_parent, m_startRow + 3, DetailColumn, editWidgets["memo"]); arrangeWidget(m_parent, m_startRow + 0, PaymentColumn, editWidgets["payment"]); arrangeWidget(m_parent, m_startRow + 0, DepositColumn, editWidgets["deposit"]); // increase the height of the row containing the memo widget m_parent->setRowHeight(m_startRow + 3, m_parent->rowHeightHint() * 3); } void StdTransaction::tabOrderInRegister(QWidgetList& tabOrderWidgets) const { QStringList taborder = KMyMoneyGlobalSettings::stdTransactionRegisterTabOrder().split(',', QString::SkipEmptyParts); QStringList::const_iterator it_s = taborder.constBegin(); QWidget* w; while (it_s != taborder.constEnd()) { if (*it_s == "number") { if (haveNumberField()) { if ((w = focusWidget(m_parent->cellWidget(m_startRow + 0, NumberColumn)))) tabOrderWidgets.append(w); } } else if (*it_s == "date") { tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, DateColumn))); } else if (*it_s == "payee") { tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, DetailColumn))); } else if (*it_s == "category") { // make sure to have the category field and the split button as separate tab order widgets // ok, we have to have some internal knowledge about the KMyMoneyCategory object, but // it's one of our own widgets, so we actually don't care. Just make sure, that we don't // go haywire when someone changes the KMyMoneyCategory object ... w = m_parent->cellWidget(m_startRow + 1, DetailColumn); tabOrderWidgets.append(focusWidget(w)); w = w->findChild("splitButton"); if (w) tabOrderWidgets.append(w); } else if (*it_s == "tag") { tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 2, DetailColumn))); } else if (*it_s == "memo") { tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 3, DetailColumn))); } else if (*it_s == "payment") { tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, PaymentColumn))); } else if (*it_s == "deposit") { tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, DepositColumn))); } else if (*it_s == "state") { tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 1, DateColumn))); } ++it_s; } } int StdTransaction::numRowsRegister(bool expanded) const { int numRows = 1; if (expanded) { numRows = 4; if (!m_inEdit) { //When not in edit Tags haven't a separate row; numRows--; if (m_payee.isEmpty()) { numRows--; } if (m_split.memo().isEmpty()) { numRows--; } // For income and expense accounts that only have // two splits we only show one line, because the // account name is already contained in the account column. if (m_account.accountType() == eMyMoney::Account::Income || m_account.accountType() == eMyMoney::Account::Expense) { if (numRows > 2 && m_transaction.splitCount() == 2) numRows = 1; } } } return numRows; } TransactionEditor* StdTransaction::createEditor(TransactionEditorContainer* regForm, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate) { #ifndef KMM_DESIGNER m_inRegisterEdit = regForm == m_parent; return new StdTransactionEditor(regForm, this, list, lastPostDate); #else return NULL; #endif } InvestTransaction::InvestTransaction(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId) : Transaction(parent, transaction, split, uniqueId) { #ifndef KMM_DESIGNER // dissect the transaction into its type, splits, currency, security etc. KMyMoneyUtils::dissectTransaction(m_transaction, m_split, m_assetAccountSplit, m_feeSplits, m_interestSplits, m_security, m_currency, m_transactionType); #endif QList::ConstIterator it_s; for (it_s = m_feeSplits.constBegin(); it_s != m_feeSplits.constEnd(); ++it_s) { m_feeAmount += (*it_s).value(); } for (it_s = m_interestSplits.constBegin(); it_s != m_interestSplits.constEnd(); ++it_s) { m_interestAmount += (*it_s).value(); } // check the count of the fee splits and setup the text switch (m_feeSplits.count()) { case 0: break; case 1: m_feeCategory = MyMoneyFile::instance()->accountToCategory(m_feeSplits[0].accountId()); break; default: m_feeCategory = i18nc("Split transaction (category replacement)", "Split transaction"); break; } // check the count of the interest splits and setup the text switch (m_interestSplits.count()) { case 0: break; case 1: m_interestCategory = MyMoneyFile::instance()->accountToCategory(m_interestSplits[0].accountId()); break; default: m_interestCategory = i18nc("Split transaction (category replacement)", "Split transaction"); break; } m_rowsForm = 7; // setup initial size setNumRowsRegister(numRowsRegister(KMyMoneyGlobalSettings::showRegisterDetailed())); emit parent->itemAdded(this); } void InvestTransaction::setupForm(TransactionForm* form) { Transaction::setupForm(form); form->setSpan(5, 1, 2, 1); } void InvestTransaction::activity(QString& txt, eMyMoney::Split::InvestmentTransactionType type) const { switch (type) { case eMyMoney::Split::InvestmentTransactionType::AddShares: txt = i18n("Add shares"); break; case eMyMoney::Split::InvestmentTransactionType::RemoveShares: txt = i18n("Remove shares"); break; case eMyMoney::Split::InvestmentTransactionType::BuyShares: txt = i18n("Buy shares"); break; case eMyMoney::Split::InvestmentTransactionType::SellShares: txt = i18n("Sell shares"); break; case eMyMoney::Split::InvestmentTransactionType::Dividend: txt = i18n("Dividend"); break; case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend: txt = i18n("Reinvest Dividend"); break; case eMyMoney::Split::InvestmentTransactionType::Yield: txt = i18n("Yield"); break; case eMyMoney::Split::InvestmentTransactionType::SplitShares: txt = i18n("Split shares"); break; case eMyMoney::Split::InvestmentTransactionType::InterestIncome: txt = i18n("Interest Income"); break; default: txt = i18nc("Unknown investment activity", "Unknown"); break; } } bool InvestTransaction::formCellText(QString& txt, Qt::Alignment& align, int row, int col, QPainter* /* painter */) { bool fieldEditable = false; switch (row) { case 0: switch (col) { case LabelColumn1: align |= Qt::AlignLeft; txt = i18n("Activity"); break; case ValueColumn1: align |= Qt::AlignLeft; fieldEditable = true; activity(txt, m_transactionType); break; case LabelColumn2: align |= Qt::AlignLeft; txt = i18n("Date"); break; case ValueColumn2: align |= Qt::AlignRight; fieldEditable = true; if (m_transaction != MyMoneyTransaction()) txt = QLocale().toString(m_transaction.postDate(), QLocale::ShortFormat); break; } break; case 1: switch (col) { case LabelColumn1: align |= Qt::AlignLeft; txt = i18n("Security"); break; case ValueColumn1: align |= Qt::AlignLeft; fieldEditable = true; if (m_account.isInvest()) txt = m_security.name(); break; case LabelColumn2: align |= Qt::AlignLeft; if (haveShares()) { txt = i18n("Shares"); } else if (haveSplitRatio()) { txt = i18n("Ratio"); } break; case ValueColumn2: align |= Qt::AlignRight; if ((fieldEditable = haveShares()) == true) { txt = m_split.shares().abs().formatMoney("", MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction())); } else if (haveSplitRatio()) { txt = QString("1 / %1").arg(m_split.shares().abs().formatMoney("", -1)); } break; } break; case 2: switch (col) { case LabelColumn1: align |= Qt::AlignLeft; if (haveAssetAccount()) txt = i18n("Account"); break; case ValueColumn1: align |= Qt::AlignLeft; if ((fieldEditable = haveAssetAccount()) == true) { txt = MyMoneyFile::instance()->accountToCategory(m_assetAccountSplit.accountId()); } break; case LabelColumn2: align |= Qt::AlignLeft; if (havePrice()) txt = i18n("Price/share"); break; case ValueColumn2: align |= Qt::AlignRight; if ((fieldEditable = havePrice()) == true && !m_split.shares().isZero()) { txt = m_split.price().formatMoney("", m_security.pricePrecision()); } break; } break; case 3: switch (col) { case LabelColumn1: align |= Qt::AlignLeft; if (haveFees()) txt = i18n("Fees"); break; case ValueColumn1: align |= Qt::AlignLeft; if ((fieldEditable = haveFees()) == true) { txt = m_feeCategory; } break; case LabelColumn2: align |= Qt::AlignLeft; if (haveFees() && !m_feeCategory.isEmpty()) txt = i18n("Fee Amount"); break; case ValueColumn2: align |= Qt::AlignRight; if (haveFees()) { if ((fieldEditable = !m_feeCategory.isEmpty()) == true) { txt = MyMoneyUtils::formatMoney(m_feeAmount, m_currency); } } break; } break; case 4: switch (col) { case LabelColumn1: align |= Qt::AlignLeft; if (haveInterest()) txt = i18n("Interest"); break; case ValueColumn1: align |= Qt::AlignLeft; if ((fieldEditable = haveInterest()) == true) { txt = m_interestCategory; } break; case LabelColumn2: align |= Qt::AlignLeft; if (haveInterest() && !m_interestCategory.isEmpty()) txt = i18n("Interest"); break; case ValueColumn2: align |= Qt::AlignRight; if (haveInterest()) { if ((fieldEditable = !m_interestCategory.isEmpty()) == true) { txt = MyMoneyUtils::formatMoney(-m_interestAmount, m_currency); } } break; } break; case 5: switch (col) { case LabelColumn1: align |= Qt::AlignLeft; txt = i18n("Memo"); break; case ValueColumn1: align &= ~Qt::AlignVCenter; align |= Qt::AlignTop; align |= Qt::AlignLeft; fieldEditable = true; if (m_transaction != MyMoneyTransaction()) txt = m_split.memo().section('\n', 0, 2); break; case LabelColumn2: align |= Qt::AlignLeft; if (haveAmount()) txt = i18nc("Total balance", "Total"); break; case ValueColumn2: align |= Qt::AlignRight; if ((fieldEditable = haveAmount()) == true) { txt = m_assetAccountSplit.value().abs() .formatMoney(m_currency.tradingSymbol(), MyMoneyMoney::denomToPrec(m_currency.smallestAccountFraction())); } } break; case 6: switch (col) { case LabelColumn2: align |= Qt::AlignLeft; txt = i18n("Status"); break; case ValueColumn2: align |= Qt::AlignRight; fieldEditable = true; txt = reconcileState(); break; } } return fieldEditable; } void InvestTransaction::registerCellText(QString& txt, Qt::Alignment& align, int row, int col, QPainter* /* painter */) { switch (row) { case 0: switch (col) { case DateColumn: align |= Qt::AlignLeft; txt = QLocale().toString(m_transaction.postDate(), QLocale::ShortFormat); break; case DetailColumn: align |= Qt::AlignLeft; activity(txt, m_transactionType); break; case SecurityColumn: align |= Qt::AlignLeft; if (m_account.isInvest()) txt = m_security.name(); break; case ReconcileFlagColumn: align |= Qt::AlignHCenter; txt = reconcileState(false); break; case QuantityColumn: align |= Qt::AlignRight; if (haveShares()) txt = m_split.shares().abs().formatMoney("", MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction())); else if (haveSplitRatio()) { txt = QString("1 / %1").arg(m_split.shares().abs().formatMoney("", -1)); } break; case PriceColumn: align |= Qt::AlignRight; if (havePrice() && !m_split.shares().isZero()) { txt = m_split.price().formatMoney(m_currency.tradingSymbol(), m_security.pricePrecision()); } break; case ValueColumn: align |= Qt::AlignRight; if (haveAmount()) { txt = MyMoneyUtils::formatMoney(m_assetAccountSplit.value().abs(), m_currency); } else if (haveInterest()) { txt = MyMoneyUtils::formatMoney(-m_interestAmount, m_currency); } break; case BalanceColumn: align |= Qt::AlignRight; if (m_showBalance) txt = m_balance.formatMoney("", MyMoneyMoney::denomToPrec(m_security.smallestAccountFraction())); else txt = "----"; break; default: break; } break; case 1: switch (col) { case DetailColumn: align |= Qt::AlignLeft; if (haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty()) { txt = MyMoneyFile::instance()->accountToCategory(m_assetAccountSplit.accountId()); } else if (haveInterest() && m_interestSplits.count()) { txt = m_interestCategory; } else if (haveFees() && m_feeSplits.count()) { txt = m_feeCategory; } else singleLineMemo(txt, m_split); break; case QuantityColumn: align |= Qt::AlignRight; if (haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty()) { // txt = m_interestAmount.abs().formatMoney(m_currency); } else if (haveInterest() && m_interestSplits.count()) { txt = MyMoneyUtils::formatMoney(-m_interestAmount, m_currency); } else if (haveFees() && m_feeSplits.count()) { txt = MyMoneyUtils::formatMoney(m_feeAmount, m_currency); } break; default: break; } break; case 2: switch (col) { case DetailColumn: align |= Qt::AlignLeft; if (haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty() && haveInterest() && m_interestSplits.count()) { txt = m_interestCategory; } else if (haveFees() && m_feeSplits.count()) { txt = m_feeCategory; } else singleLineMemo(txt, m_split); break; case QuantityColumn: align |= Qt::AlignRight; if (haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty() && haveInterest() && m_interestSplits.count()) { txt = MyMoneyUtils::formatMoney(-m_interestAmount, m_currency); } else if (haveFees() && m_feeSplits.count()) { txt = MyMoneyUtils::formatMoney(m_feeAmount, m_currency); } break; default: break; } break; case 3: switch (col) { case DetailColumn: align |= Qt::AlignLeft; if (haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty() && haveInterest() && m_interestSplits.count() && haveFees() && m_feeSplits.count()) { txt = m_feeCategory; } else singleLineMemo(txt, m_split); break; case QuantityColumn: align |= Qt::AlignRight; if (haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty() && haveInterest() && m_interestSplits.count() && haveFees() && m_feeSplits.count()) { txt = MyMoneyUtils::formatMoney(m_feeAmount, m_currency); } break; default: break; } break; case 4: switch (col) { case DetailColumn: align |= Qt::AlignLeft; singleLineMemo(txt, m_split); break; default: break; } break; } } int InvestTransaction::registerColWidth(int col, const QFontMetrics& cellFontMetrics) { QString txt; MyMoneyMoney amount; int nw = 0; // for now just check all rows in that column for (int row = 0; row < m_rowsRegister; ++row) { int w; Transaction::registerCellText(txt, row, col); w = cellFontMetrics.width(txt + " "); nw = qMax(nw, w); } // TODO the optimized way would be to base the size on the contents of a single row // as we do it in StdTransaction::registerColWidth() #if 0 switch (col) { default: break; case PriceColumn: if (havePrice()) { txt = (m_split.value() / m_split.shares()).formatMoney("", KMyMoneyGlobalSettings::pricePrecision()); nw = cellFontMetrics.width(txt + " "); } break; } #endif return nw; } void InvestTransaction::arrangeWidgetsInForm(QMap& editWidgets) { if (!m_form || !m_parent) return; setupFormPalette(editWidgets); // arrange the edit widgets arrangeWidget(m_form, 0, ValueColumn1, editWidgets["activity"]); arrangeWidget(m_form, 0, ValueColumn2, editWidgets["postdate"]); arrangeWidget(m_form, 1, ValueColumn1, editWidgets["security"]); arrangeWidget(m_form, 1, ValueColumn2, editWidgets["shares"]); arrangeWidget(m_form, 2, ValueColumn1, editWidgets["asset-account"]); arrangeWidget(m_form, 2, ValueColumn2, editWidgets["price"]); arrangeWidget(m_form, 3, ValueColumn1, editWidgets["fee-account"]->parentWidget()); arrangeWidget(m_form, 3, ValueColumn2, editWidgets["fee-amount"]); arrangeWidget(m_form, 4, ValueColumn1, editWidgets["interest-account"]->parentWidget()); arrangeWidget(m_form, 4, ValueColumn2, editWidgets["interest-amount"]); arrangeWidget(m_form, 5, ValueColumn1, editWidgets["memo"]); arrangeWidget(m_form, 5, ValueColumn2, editWidgets["total"]); arrangeWidget(m_form, 6, ValueColumn2, editWidgets["status"]); // arrange dynamic labels arrangeWidget(m_form, 0, LabelColumn1, editWidgets["activity-label"]); arrangeWidget(m_form, 0, LabelColumn2, editWidgets["postdate-label"]); arrangeWidget(m_form, 1, LabelColumn1, editWidgets["security-label"]); arrangeWidget(m_form, 1, LabelColumn2, editWidgets["shares-label"]); arrangeWidget(m_form, 2, LabelColumn1, editWidgets["asset-label"]); arrangeWidget(m_form, 2, LabelColumn2, editWidgets["price-label"]); arrangeWidget(m_form, 3, LabelColumn1, editWidgets["fee-label"]); arrangeWidget(m_form, 3, LabelColumn2, editWidgets["fee-amount-label"]); arrangeWidget(m_form, 4, LabelColumn1, editWidgets["interest-label"]); arrangeWidget(m_form, 4, LabelColumn2, editWidgets["interest-amount-label"]); arrangeWidget(m_form, 5, LabelColumn1, editWidgets["memo-label"]); arrangeWidget(m_form, 5, LabelColumn2, editWidgets["total-label"]); arrangeWidget(m_form, 6, LabelColumn2, editWidgets["status-label"]); // get rid of the hints. we don't need them for the form QMap::iterator it; for (it = editWidgets.begin(); it != editWidgets.end(); ++it) { KMyMoneyCombo* combo = dynamic_cast(*it); kMyMoneyLineEdit* lineedit = dynamic_cast(*it); kMyMoneyEdit* edit = dynamic_cast(*it); KMyMoneyPayeeCombo* payee = dynamic_cast(*it); if (combo) combo->setPlaceholderText(QString()); if (edit) edit->setPlaceholderText(QString()); if (lineedit) lineedit->setPlaceholderText(QString()); if (payee) payee->setPlaceholderText(QString()); } } void InvestTransaction::tabOrderInForm(QWidgetList& tabOrderWidgets) const { // activity tabOrderWidgets.append(focusWidget(m_form->cellWidget(0, ValueColumn1))); // date tabOrderWidgets.append(focusWidget(m_form->cellWidget(0, ValueColumn2))); // security tabOrderWidgets.append(focusWidget(m_form->cellWidget(1, ValueColumn1))); // shares tabOrderWidgets.append(focusWidget(m_form->cellWidget(1, ValueColumn2))); // account tabOrderWidgets.append(focusWidget(m_form->cellWidget(2, ValueColumn1))); // price tabOrderWidgets.append(focusWidget(m_form->cellWidget(2, ValueColumn2))); // make sure to have the fee category field and the split button as separate tab order widgets // ok, we have to have some internal knowledge about the KMyMoneyCategory object, but // it's one of our own widgets, so we actually don't care. Just make sure, that we don't // go haywire when someone changes the KMyMoneyCategory object ... QWidget* w = m_form->cellWidget(3, ValueColumn1); tabOrderWidgets.append(focusWidget(w)); w = w->findChild("splitButton"); if (w) tabOrderWidgets.append(w); // fee amount tabOrderWidgets.append(focusWidget(m_form->cellWidget(3, ValueColumn2))); // the same applies for the interest categories w = m_form->cellWidget(4, ValueColumn1); tabOrderWidgets.append(focusWidget(w)); w = w->findChild("splitButton"); if (w) tabOrderWidgets.append(w); // interest amount tabOrderWidgets.append(focusWidget(m_form->cellWidget(4, ValueColumn2))); // memo tabOrderWidgets.append(focusWidget(m_form->cellWidget(5, ValueColumn1))); // state tabOrderWidgets.append(focusWidget(m_form->cellWidget(6, ValueColumn2))); } void InvestTransaction::arrangeWidgetsInRegister(QMap& editWidgets) { if (!m_parent) return; setupRegisterPalette(editWidgets); arrangeWidget(m_parent, m_startRow + 0, DateColumn, editWidgets["postdate"]); arrangeWidget(m_parent, m_startRow + 0, SecurityColumn, editWidgets["security"]); arrangeWidget(m_parent, m_startRow + 0, DetailColumn, editWidgets["activity"]); arrangeWidget(m_parent, m_startRow + 1, DetailColumn, editWidgets["asset-account"]); arrangeWidget(m_parent, m_startRow + 2, DetailColumn, editWidgets["interest-account"]->parentWidget()); arrangeWidget(m_parent, m_startRow + 3, DetailColumn, editWidgets["fee-account"]->parentWidget()); arrangeWidget(m_parent, m_startRow + 4, DetailColumn, editWidgets["memo"]); arrangeWidget(m_parent, m_startRow + 0, QuantityColumn, editWidgets["shares"]); arrangeWidget(m_parent, m_startRow + 0, PriceColumn, editWidgets["price"]); arrangeWidget(m_parent, m_startRow + 2, QuantityColumn, editWidgets["interest-amount"]); arrangeWidget(m_parent, m_startRow + 3, QuantityColumn, editWidgets["fee-amount"]); arrangeWidget(m_parent, m_startRow + 0, ValueColumn, editWidgets["total"]); arrangeWidget(m_parent, m_startRow + 1, DateColumn, editWidgets["status"]); // increase the height of the row containing the memo widget m_parent->setRowHeight(m_startRow + 4, m_parent->rowHeightHint() * 3); } void InvestTransaction::tabOrderInRegister(QWidgetList& tabOrderWidgets) const { QWidget* w; // date tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, DateColumn))); // security tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, SecurityColumn))); // activity tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, DetailColumn))); // shares tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, QuantityColumn))); // price tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 0, PriceColumn))); // asset account tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 1, DetailColumn))); // make sure to have the category fields and the split button as separate tab order widgets // ok, we have to have some internal knowledge about the KMyMoneyCategory object, but // it's one of our own widgets, so we actually don't care. Just make sure, that we don't // go haywire when someone changes the KMyMoneyCategory object ... w = m_parent->cellWidget(m_startRow + 2, DetailColumn); // interest account tabOrderWidgets.append(focusWidget(w)); w = w->findChild("splitButton"); if (w) tabOrderWidgets.append(w); // interest amount tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 2, QuantityColumn))); w = m_parent->cellWidget(m_startRow + 3, DetailColumn); // fee account tabOrderWidgets.append(focusWidget(w)); w = w->findChild("splitButton"); if (w) tabOrderWidgets.append(w); // fee amount tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 3, QuantityColumn))); // memo tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 4, DetailColumn))); // status tabOrderWidgets.append(focusWidget(m_parent->cellWidget(m_startRow + 1, DateColumn))); } int InvestTransaction::numRowsRegister(bool expanded) const { int numRows = 1; if (expanded) { if (!m_inEdit) { if (haveAssetAccount() && !m_assetAccountSplit.accountId().isEmpty()) ++numRows; if (haveInterest() && m_interestSplits.count()) ++numRows; if (haveFees() && m_feeSplits.count()) ++numRows; if (!m_split.memo().isEmpty()) ++numRows; } else numRows = 5; } return numRows; } bool InvestTransaction::haveShares() const { bool rc = true; switch (m_transactionType) { case eMyMoney::Split::InvestmentTransactionType::Dividend: case eMyMoney::Split::InvestmentTransactionType::Yield: case eMyMoney::Split::InvestmentTransactionType::SplitShares: case eMyMoney::Split::InvestmentTransactionType::InterestIncome: rc = false; break; default: break; } return rc; } bool InvestTransaction::haveFees() const { bool rc = true; switch (m_transactionType) { case eMyMoney::Split::InvestmentTransactionType::AddShares: case eMyMoney::Split::InvestmentTransactionType::RemoveShares: case eMyMoney::Split::InvestmentTransactionType::SplitShares: rc = false; break; default: break; } return rc; } bool InvestTransaction::haveInterest() const { bool rc = false; switch (m_transactionType) { case eMyMoney::Split::InvestmentTransactionType::BuyShares: case eMyMoney::Split::InvestmentTransactionType::SellShares: case eMyMoney::Split::InvestmentTransactionType::Dividend: case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend: case eMyMoney::Split::InvestmentTransactionType::Yield: case eMyMoney::Split::InvestmentTransactionType::InterestIncome: rc = true; break; default: break; } return rc; } bool InvestTransaction::havePrice() const { bool rc = false; switch (m_transactionType) { case eMyMoney::Split::InvestmentTransactionType::BuyShares: case eMyMoney::Split::InvestmentTransactionType::SellShares: case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend: rc = true; break; default: break; } return rc; } bool InvestTransaction::haveAmount() const { bool rc = false; switch (m_transactionType) { case eMyMoney::Split::InvestmentTransactionType::BuyShares: case eMyMoney::Split::InvestmentTransactionType::SellShares: case eMyMoney::Split::InvestmentTransactionType::Dividend: case eMyMoney::Split::InvestmentTransactionType::Yield: case eMyMoney::Split::InvestmentTransactionType::InterestIncome: rc = true; break; default: break; } return rc; } bool InvestTransaction::haveAssetAccount() const { bool rc = true; switch (m_transactionType) { case eMyMoney::Split::InvestmentTransactionType::AddShares: case eMyMoney::Split::InvestmentTransactionType::RemoveShares: case eMyMoney::Split::InvestmentTransactionType::SplitShares: case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend: rc = false; break; default: break; } return rc; } bool InvestTransaction::haveSplitRatio() const { return m_transactionType == eMyMoney::Split::InvestmentTransactionType::SplitShares; } void InvestTransaction::splits(MyMoneySplit& assetAccountSplit, QList& interestSplits, QList& feeSplits) const { assetAccountSplit = m_assetAccountSplit; interestSplits = m_interestSplits; feeSplits = m_feeSplits; } TransactionEditor* InvestTransaction::createEditor(TransactionEditorContainer* regForm, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate) { #ifndef KMM_DESIGNER m_inRegisterEdit = regForm == m_parent; return new InvestTransactionEditor(regForm, this, list, lastPostDate); #else return NULL; #endif } diff --git a/kmymoney/wizards/endingbalancedlg/kendingbalancedlg.cpp b/kmymoney/wizards/endingbalancedlg/kendingbalancedlg.cpp index 21bd2ae08..34ee3ed63 100644 --- a/kmymoney/wizards/endingbalancedlg/kendingbalancedlg.cpp +++ b/kmymoney/wizards/endingbalancedlg/kendingbalancedlg.cpp @@ -1,388 +1,389 @@ /*************************************************************************** kendingbalancedlg.cpp ------------------- copyright : (C) 2000,2003 by Michael Edwardes, Thomas Baumgart email : mte@users.sourceforge.net ipwizard@users.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "kendingbalancedlg.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include +#include // ---------------------------------------------------------------------------- // KDE Includes #include #include // ---------------------------------------------------------------------------- // Project Includes #include "mymoneyutils.h" #include "kmymoneyedit.h" #include "mymoneysplit.h" #include "mymoneyfile.h" #include "mymoneyinstitution.h" #include "mymoneyaccount.h" #include "mymoneypayee.h" #include "mymoneytransaction.h" #include "kmymoneycategory.h" #include "kmymoneyaccountselector.h" #include "kmymoneyutils.h" #include "kcurrencycalculator.h" #include "kmymoneysettings.h" class KEndingBalanceDlg::Private { public: explicit Private(int numPages) : m_pages(numPages, true) {} MyMoneyTransaction m_tInterest; MyMoneyTransaction m_tCharges; MyMoneyAccount m_account; QMap m_helpAnchor; QBitArray m_pages; }; KEndingBalanceDlg::KEndingBalanceDlg(const MyMoneyAccount& account, QWidget *parent) : KEndingBalanceDlgDecl(parent), d(new Private(Page_InterestChargeCheckings + 1)) { setModal(true); QString value; MyMoneyMoney endBalance, startBalance; d->m_account = account; MyMoneySecurity currency = MyMoneyFile::instance()->security(account.currencyId()); //FIXME: port m_statementInfoPageCheckings->m_enterInformationLabel->setText(QString("") + i18n("Please enter the following fields with the information as you find them on your statement. Make sure to enter all values in %1.", currency.name()) + QString("")); // If the previous reconciliation was postponed, // we show a different first page value = account.value("lastReconciledBalance"); if (value.isEmpty()) { // if the last statement has been entered long enough ago (more than one month), // then take the last statement date and add one month and use that as statement // date. QDate lastStatementDate = account.lastReconciliationDate(); if (lastStatementDate.addMonths(1) < QDate::currentDate()) { setField("statementDate", lastStatementDate.addMonths(1)); } slotUpdateBalances(); d->m_pages.clearBit(Page_PreviousPostpone); } else { d->m_pages.clearBit(Page_CheckingStart); d->m_pages.clearBit(Page_InterestChargeCheckings); //removePage(m_interestChargeCheckings); // make sure, we show the correct start page setStartId(Page_PreviousPostpone); MyMoneyMoney factor(1, 1); if (d->m_account.accountGroup() == eMyMoney::Account::Liability) factor = -factor; startBalance = MyMoneyMoney(value) * factor; value = account.value("statementBalance"); endBalance = MyMoneyMoney(value) * factor; //FIXME: port m_statementInfoPageCheckings->m_previousBalance->setValue(startBalance); m_statementInfoPageCheckings->m_endingBalance->setValue(endBalance); } // We don't need to add the default into the list (see ::help() why) - // m_helpAnchor[m_startPageCheckings] = QString(""); + // m_helpAnchor[m_startPageCheckings] = QString(QString()); d->m_helpAnchor[m_interestChargeCheckings] = QString("details.reconcile.wizard.interest"); d->m_helpAnchor[m_statementInfoPageCheckings] = QString("details.reconcile.wizard.statement"); value = account.value("statementDate"); if (!value.isEmpty()) setField("statementDate", QDate::fromString(value, Qt::ISODate)); //FIXME: port m_statementInfoPageCheckings->m_lastStatementDate->setText(QString()); if (account.lastReconciliationDate().isValid()) { m_statementInfoPageCheckings->m_lastStatementDate->setText(i18n("Last reconciled statement: %1", QLocale().toString(account.lastReconciliationDate()))); } // connect the signals with the slots connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotReloadEditWidgets())); connect(m_statementInfoPageCheckings->m_statementDate, SIGNAL(dateChanged(QDate)), this, SLOT(slotUpdateBalances())); connect(m_interestChargeCheckings->m_interestCategoryEdit, SIGNAL(createItem(QString,QString&)), this, SLOT(slotCreateInterestCategory(QString,QString&))); connect(m_interestChargeCheckings->m_chargesCategoryEdit, SIGNAL(createItem(QString,QString&)), this, SLOT(slotCreateChargesCategory(QString,QString&))); connect(m_interestChargeCheckings->m_payeeEdit, SIGNAL(createItem(QString,QString&)), this, SIGNAL(createPayee(QString,QString&))); KMyMoneyMVCCombo::setSubstringSearchForChildren(m_interestChargeCheckings, !KMyMoneySettings::stringMatchFromStart()); slotReloadEditWidgets(); // preset payee if possible try { // if we find a payee with the same name as the institution, // than this is what we use as payee. if (!d->m_account.institutionId().isEmpty()) { MyMoneyInstitution inst = MyMoneyFile::instance()->institution(d->m_account.institutionId()); MyMoneyPayee payee = MyMoneyFile::instance()->payeeByName(inst.name()); setField("payeeEdit", payee.id()); } } catch (const MyMoneyException &) { } KMyMoneyUtils::updateWizardButtons(this); // setup different text and icon on finish button setButtonText(QWizard::FinishButton, KStandardGuiItem::cont().text()); button(QWizard::FinishButton)->setIcon(KStandardGuiItem::cont().icon()); } KEndingBalanceDlg::~KEndingBalanceDlg() { delete d; } void KEndingBalanceDlg::slotUpdateBalances() { MYMONEYTRACER(tracer); // determine the beginning balance and ending balance based on the following // forumulas: // // end balance = current balance - sum(all non cleared transactions) // - sum(all cleared transactions posted // after statement date) // start balance = end balance - sum(all cleared transactions // up to statement date) MyMoneyTransactionFilter filter(d->m_account.id()); filter.addState((int)eMyMoney::TransactionFilter::State::NotReconciled); filter.setReportAllSplits(true); QList > transactionList; QList >::const_iterator it; // retrieve the list from the engine MyMoneyFile::instance()->transactionList(transactionList, filter); //first retrieve the oldest not reconciled transaction QDate oldestTransactionDate; it = transactionList.constBegin(); if (it != transactionList.constEnd()) { oldestTransactionDate = (*it).first.postDate(); m_statementInfoPageCheckings->m_oldestTransactionDate->setText(i18n("Oldest unmarked transaction: %1", QLocale().toString(oldestTransactionDate))); } filter.addState((int)eMyMoney::TransactionFilter::State::Cleared); // retrieve the list from the engine to calculate the starting and ending balance MyMoneyFile::instance()->transactionList(transactionList, filter); MyMoneyMoney balance = MyMoneyFile::instance()->balance(d->m_account.id()); MyMoneyMoney factor(1, 1); if (d->m_account.accountGroup() == eMyMoney::Account::Liability) factor = -factor; MyMoneyMoney endBalance, startBalance; balance = balance * factor; endBalance = startBalance = balance; - tracer.printf("total balance = %s", qPrintable(endBalance.formatMoney("", 2))); + tracer.printf("total balance = %s", qPrintable(endBalance.formatMoney(QString(), 2))); for (it = transactionList.constBegin(); it != transactionList.constEnd(); ++it) { const MyMoneySplit& split = (*it).second; balance -= split.shares() * factor; if ((*it).first.postDate() > field("statementDate").toDate()) { - tracer.printf("Reducing balances by %s because postdate of %s/%s(%s) is past statement date", qPrintable((split.shares() * factor).formatMoney("", 2)), qPrintable((*it).first.id()), qPrintable(split.id()), qPrintable((*it).first.postDate().toString(Qt::ISODate))); + tracer.printf("Reducing balances by %s because postdate of %s/%s(%s) is past statement date", qPrintable((split.shares() * factor).formatMoney(QString(), 2)), qPrintable((*it).first.id()), qPrintable(split.id()), qPrintable((*it).first.postDate().toString(Qt::ISODate))); endBalance -= split.shares() * factor; startBalance -= split.shares() * factor; } else { switch (split.reconcileFlag()) { case eMyMoney::Split::State::NotReconciled: - tracer.printf("Reducing balances by %s because %s/%s(%s) is not reconciled", qPrintable((split.shares() * factor).formatMoney("", 2)), qPrintable((*it).first.id()), qPrintable(split.id()), qPrintable((*it).first.postDate().toString(Qt::ISODate))); + tracer.printf("Reducing balances by %s because %s/%s(%s) is not reconciled", qPrintable((split.shares() * factor).formatMoney(QString(), 2)), qPrintable((*it).first.id()), qPrintable(split.id()), qPrintable((*it).first.postDate().toString(Qt::ISODate))); endBalance -= split.shares() * factor; startBalance -= split.shares() * factor; break; case eMyMoney::Split::State::Cleared: - tracer.printf("Reducing start balance by %s because %s/%s(%s) is cleared", qPrintable((split.shares() * factor).formatMoney("", 2)), qPrintable((*it).first.id()), qPrintable(split.id()), qPrintable((*it).first.postDate().toString(Qt::ISODate))); + tracer.printf("Reducing start balance by %s because %s/%s(%s) is cleared", qPrintable((split.shares() * factor).formatMoney(QString(), 2)), qPrintable((*it).first.id()), qPrintable(split.id()), qPrintable((*it).first.postDate().toString(Qt::ISODate))); startBalance -= split.shares() * factor; break; default: break; } } } //FIXME: port m_statementInfoPageCheckings->m_previousBalance->setValue(startBalance); m_statementInfoPageCheckings->m_endingBalance->setValue(endBalance); - tracer.printf("total balance = %s", qPrintable(endBalance.formatMoney("", 2))); - tracer.printf("start balance = %s", qPrintable(startBalance.formatMoney("", 2))); + tracer.printf("total balance = %s", qPrintable(endBalance.formatMoney(QString(), 2))); + tracer.printf("start balance = %s", qPrintable(startBalance.formatMoney(QString(), 2))); setField("interestDateEdit", field("statementDate").toDate()); setField("chargesDateEdit", field("statementDate").toDate()); } void KEndingBalanceDlg::accept() { if ((!field("interestEditValid").toBool() || createTransaction(d->m_tInterest, -1, field("interestEdit").value(), field("interestCategoryEdit").toString(), field("interestDateEdit").toDate())) && (!field("chargesEditValid").toBool() || createTransaction(d->m_tCharges, 1, field("chargesEdit").value(), field("chargesCategoryEdit").toString(), field("chargesDateEdit").toDate()))) KEndingBalanceDlgDecl::accept(); } void KEndingBalanceDlg::slotCreateInterestCategory(const QString& txt, QString& id) { createCategory(txt, id, MyMoneyFile::instance()->income()); } void KEndingBalanceDlg::slotCreateChargesCategory(const QString& txt, QString& id) { createCategory(txt, id, MyMoneyFile::instance()->expense()); } void KEndingBalanceDlg::createCategory(const QString& txt, QString& id, const MyMoneyAccount& parent) { MyMoneyAccount acc; acc.setName(txt); emit createCategory(acc, parent); id = acc.id(); } const MyMoneyMoney KEndingBalanceDlg::endingBalance() const { return adjustedReturnValue(m_statementInfoPageCheckings->m_endingBalance->value()); } const MyMoneyMoney KEndingBalanceDlg::previousBalance() const { return adjustedReturnValue(m_statementInfoPageCheckings->m_previousBalance->value()); } const MyMoneyMoney KEndingBalanceDlg::adjustedReturnValue(const MyMoneyMoney& v) const { return d->m_account.accountGroup() == eMyMoney::Account::Liability ? -v : v; } void KEndingBalanceDlg::slotReloadEditWidgets() { QString payeeId, interestId, chargesId; // keep current selected items payeeId = field("payeeEdit").toString(); interestId = field("interestCategoryEdit").toString(); chargesId = field("chargesCategoryEdit").toString(); // load the payee and category widgets with data from the engine //FIXME: port m_interestChargeCheckings->m_payeeEdit->loadPayees(MyMoneyFile::instance()->payeeList()); // a user request to show all categories in both selectors due to a valid use case. AccountSet aSet; aSet.addAccountGroup(eMyMoney::Account::Expense); aSet.addAccountGroup(eMyMoney::Account::Income); //FIXME: port aSet.load(m_interestChargeCheckings->m_interestCategoryEdit->selector()); aSet.load(m_interestChargeCheckings->m_chargesCategoryEdit->selector()); // reselect currently selected items if (!payeeId.isEmpty()) setField("payeeEdit", payeeId); if (!interestId.isEmpty()) setField("interestCategoryEdit", interestId); if (!chargesId.isEmpty()) setField("chargesCategoryEdit", chargesId); } const MyMoneyTransaction KEndingBalanceDlg::interestTransaction() { return d->m_tInterest; } const MyMoneyTransaction KEndingBalanceDlg::chargeTransaction() { return d->m_tCharges; } bool KEndingBalanceDlg::createTransaction(MyMoneyTransaction &t, const int sign, const MyMoneyMoney& amount, const QString& category, const QDate& date) { t = MyMoneyTransaction(); if (category.isEmpty() || !date.isValid()) return true; MyMoneySplit s1, s2; MyMoneyMoney val = amount * MyMoneyMoney(sign, 1); try { t.setPostDate(date); t.setCommodity(d->m_account.currencyId()); s1.setPayeeId(field("payeeEdit").toString()); s1.setReconcileFlag(eMyMoney::Split::State::Cleared); s1.setAccountId(d->m_account.id()); s1.setValue(-val); s1.setShares(-val); s2 = s1; s2.setAccountId(category); s2.setValue(val); t.addSplit(s1); t.addSplit(s2); QMap priceInfo; // just empty MyMoneyMoney shares; if (!KCurrencyCalculator::setupSplitPrice(shares, t, s2, priceInfo, this)) { t = MyMoneyTransaction(); return false; } s2.setShares(shares); t.modifySplit(s2); } catch (const MyMoneyException &e) { qDebug("%s", qPrintable(e.what())); t = MyMoneyTransaction(); return false; } return true; } void KEndingBalanceDlg::help() { QString anchor = d->m_helpAnchor[currentPage()]; if (anchor.isEmpty()) anchor = QString("details.reconcile.whatis"); KHelpClient::invokeHelp(anchor); } int KEndingBalanceDlg::nextId() const { // Starting from the current page, look for the first enabled page // and return that value // If the end of the list is encountered first, then return -1. for (int i = currentId() + 1; i < d->m_pages.size() && i < pageIds().size(); ++i) { if (d->m_pages.testBit(i)) return pageIds()[i]; } return -1; } diff --git a/kmymoney/wizards/newaccountwizard/knewaccountwizard.cpp b/kmymoney/wizards/newaccountwizard/knewaccountwizard.cpp index 85fa3cb61..0c20bffa6 100644 --- a/kmymoney/wizards/newaccountwizard/knewaccountwizard.cpp +++ b/kmymoney/wizards/newaccountwizard/knewaccountwizard.cpp @@ -1,1672 +1,1673 @@ /*************************************************************************** knewaccountwizard.cpp ------------------- begin : Tue Sep 25 2006 copyright : (C) 2007 Thomas Baumgart email : Thomas Baumgart ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "knewaccountwizard.h" #include "knewaccountwizard_p.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include // ---------------------------------------------------------------------------- // Project Includes #include "kmymoneycurrencyselector.h" #include "kmymoneyaccountselector.h" #include "mymoneyfinancialcalculator.h" #include "kcurrencycalculator.h" #include "kmymoneyglobalsettings.h" #include #include "mymoneyutils.h" #include "ksplittransactiondlg.h" #include "kequitypriceupdatedlg.h" #include "accountsmodel.h" #include "accountsproxymodel.h" #include "models.h" #include "modelenums.h" #include "icons.h" #include "mymoneyfile.h" #include "mymoneyinstitution.h" #include "mymoneyaccountloan.h" #include "mymoneypayee.h" +#include "mymoneyprice.h" #include "mymoneytransaction.h" using namespace NewAccountWizard; using namespace Icons; using namespace eMyMoney; namespace NewAccountWizard { enum steps { StepInstitution = 1, StepAccount, StepBroker, StepDetails, StepPayments, StepFees, StepSchedule, StepPayout, StepParentAccount, StepFinish }; Wizard::Wizard(QWidget *parent, bool modal, Qt::WindowFlags flags) : KMyMoneyWizard(parent, modal, flags) { setTitle(i18n("KMyMoney New Account Setup")); addStep(i18n("Institution")); addStep(i18n("Account")); addStep(i18n("Broker")); addStep(i18n("Details")); addStep(i18n("Payments")); addStep(i18n("Fees")); addStep(i18n("Schedule")); addStep(i18n("Payout")); addStep(i18n("Parent Account")); addStep(i18nc("Finish the wizard", "Finish")); setStepHidden(StepBroker); setStepHidden(StepSchedule); setStepHidden(StepPayout); setStepHidden(StepDetails); setStepHidden(StepPayments); setStepHidden(StepFees); m_institutionPage = new InstitutionPage(this); m_accountTypePage = new AccountTypePage(this); // Investment Pages m_brokeragepage = new BrokeragePage(this); // Credit Card Pages m_schedulePage = new CreditCardSchedulePage(this); // Loan Pages m_generalLoanInfoPage = new GeneralLoanInfoPage(this); m_loanDetailsPage = new LoanDetailsPage(this); m_loanPaymentPage = new LoanPaymentPage(this); m_loanSchedulePage = new LoanSchedulePage(this); m_loanPayoutPage = new LoanPayoutPage(this); // Not a loan page m_hierarchyPage = new HierarchyPage(this); // Finish m_accountSummaryPage = new AccountSummaryPage(this); setFirstPage(m_institutionPage); } void Wizard::setAccount(const MyMoneyAccount& acc) { m_account = acc; m_accountTypePage->setAccount(m_account); if (!acc.institutionId().isEmpty()) { m_institutionPage->selectExistingInstitution(acc.institutionId()); } } const MyMoneySecurity& Wizard::currency() const { return m_accountTypePage->currency(); } MyMoneyMoney Wizard::interestRate() const { return m_loanDetailsPage->m_interestRate->value() / MyMoneyMoney(100, 1); } int Wizard::precision() const { return MyMoneyMoney::denomToPrec(currency().smallestAccountFraction()); } const MyMoneyAccount& Wizard::account() { m_account = MyMoneyAccountLoan(); m_account.setName(m_accountTypePage->m_accountName->text()); m_account.setOpeningDate(m_accountTypePage->m_openingDate->date()); m_account.setAccountType(m_accountTypePage->accountType()); m_account.setInstitutionId(m_institutionPage->institution().id()); m_account.setNumber(m_institutionPage->m_accountNumber->text()); m_account.setValue("iban", m_institutionPage->m_iban->text()); if (m_accountTypePage->m_preferredAccount->isChecked()) m_account.setValue("PreferredAccount", "Yes"); else m_account.deletePair("PreferredAccount"); m_account.setCurrencyId(currency().id()); if (m_account.isLoan()) { // in case we lend the money we adjust the account type if (!moneyBorrowed()) m_account.setAccountType(Account::AssetLoan); m_account.setLoanAmount(m_loanDetailsPage->m_loanAmount->value()); m_account.setInterestRate(m_loanSchedulePage->firstPaymentDueDate(), m_loanDetailsPage->m_interestRate->value()); m_account.setInterestCalculation(m_loanDetailsPage->m_paymentDue->currentIndex() == 0 ? MyMoneyAccountLoan::paymentReceived : MyMoneyAccountLoan::paymentDue); m_account.setFixedInterestRate(m_generalLoanInfoPage->m_interestType->currentIndex() == 0); m_account.setFinalPayment(m_loanDetailsPage->m_balloonAmount->value()); m_account.setTerm(m_loanDetailsPage->term()); m_account.setPeriodicPayment(m_loanDetailsPage->m_paymentAmount->value()); m_account.setPayee(m_generalLoanInfoPage->m_payee->selectedItem()); m_account.setInterestCompounding((int)m_generalLoanInfoPage->m_compoundFrequency->currentItem()); if (!m_account.fixedInterestRate()) { m_account.setNextInterestChange(m_generalLoanInfoPage->m_interestChangeDateEdit->date()); m_account.setInterestChangeFrequency(m_generalLoanInfoPage->m_interestFrequencyAmountEdit->value(), m_generalLoanInfoPage->m_interestFrequencyUnitEdit->currentIndex()); } } return m_account; } MyMoneyTransaction Wizard::payoutTransaction() { MyMoneyTransaction t; if (m_account.isLoan() // we're creating a loan && openingBalance().isZero() // and don't have an opening balance && !m_loanPayoutPage->m_noPayoutTransaction->isChecked()) { // and the user wants to have a payout transaction t.setPostDate(m_loanPayoutPage->m_payoutDate->date()); t.setCommodity(m_account.currencyId()); MyMoneySplit s; s.setAccountId(m_account.id()); s.setShares(m_loanDetailsPage->m_loanAmount->value()); if (moneyBorrowed()) s.setShares(-s.shares()); s.setValue(s.shares()); t.addSplit(s); s.clearId(); s.setValue(-s.value()); s.setAccountId(m_loanPayoutPage->payoutAccountId()); MyMoneyMoney shares; KCurrencyCalculator::setupSplitPrice(shares, t, s, QMap(), this); s.setShares(shares); t.addSplit(s); } return t; } const MyMoneyAccount& Wizard::parentAccount() { return m_accountTypePage->allowsParentAccount() ? m_hierarchyPage->parentAccount() : (m_accountTypePage->accountType() == Account::Loan ? m_generalLoanInfoPage->parentAccount() : m_accountTypePage->parentAccount()); } MyMoneyAccount Wizard::brokerageAccount() const { MyMoneyAccount account; if (m_account.accountType() == Account::Investment && m_brokeragepage->m_createBrokerageButton->isChecked()) { account.setName(m_account.brokerageName()); account.setAccountType(Account::Checkings); account.setInstitutionId(m_account.institutionId()); account.setOpeningDate(m_account.openingDate()); account.setCurrencyId(m_brokeragepage->m_brokerageCurrency->security().id()); if (m_brokeragepage->m_accountNumber->isEnabled() && !m_brokeragepage->m_accountNumber->text().isEmpty()) account.setNumber(m_brokeragepage->m_accountNumber->text()); if (m_brokeragepage->m_iban->isEnabled() && !m_brokeragepage->m_iban->text().isEmpty()) account.setValue("iban", m_brokeragepage->m_iban->text()); } return account; } const MyMoneySchedule& Wizard::schedule() { m_schedule = MyMoneySchedule(); if (!m_account.id().isEmpty()) { if (m_schedulePage->m_reminderCheckBox->isChecked() && (m_account.accountType() == Account::CreditCard)) { m_schedule.setName(m_schedulePage->m_name->text()); m_schedule.setType(Schedule::Type::Transfer); m_schedule.setPaymentType(static_cast(m_schedulePage->m_method->currentItem())); m_schedule.setFixed(false); m_schedule.setOccurrencePeriod(Schedule::Occurrence::Monthly); m_schedule.setOccurrenceMultiplier(1); MyMoneyTransaction t; MyMoneySplit s; s.setPayeeId(m_schedulePage->m_payee->selectedItem()); s.setAccountId(m_schedulePage->m_paymentAccount->selectedItem()); s.setMemo(i18n("Credit card payment")); s.setShares(-m_schedulePage->m_amount->value()); s.setValue(s.shares()); t.addSplit(s); s.clearId(); s.setAccountId(m_account.id()); s.setShares(m_schedulePage->m_amount->value()); s.setValue(s.shares()); t.addSplit(s); // setup the next due date t.setPostDate(m_schedulePage->m_date->date()); m_schedule.setTransaction(t); } else if (m_account.isLoan()) { m_schedule.setName(i18n("Loan payment for %1", m_accountTypePage->m_accountName->text())); m_schedule.setType(Schedule::Type::LoanPayment); if (moneyBorrowed()) m_schedule.setPaymentType(Schedule::PaymentType::DirectDebit); else m_schedule.setPaymentType(Schedule::PaymentType::DirectDeposit); m_schedule.setFixed(true); m_schedule.setOccurrence(m_generalLoanInfoPage->m_paymentFrequency->currentItem()); MyMoneyTransaction t; t.setCommodity(m_account.currencyId()); MyMoneySplit s; // payment split s.setPayeeId(m_generalLoanInfoPage->m_payee->selectedItem()); s.setAccountId(m_loanSchedulePage->m_paymentAccount->selectedItem()); s.setMemo(i18n("Loan payment")); s.setValue(m_loanPaymentPage->basePayment() + m_loanPaymentPage->additionalFees()); if (moneyBorrowed()) { s.setValue(-s.value()); } s.setShares(s.value()); if (m_account.id() != QLatin1String("Phony-ID")) { // if the real account is already set perform the currency conversion if it's necessary MyMoneyMoney paymentShares; KCurrencyCalculator::setupSplitPrice(paymentShares, t, s, QMap(), this); s.setShares(paymentShares); } t.addSplit(s); // principal split s.clearId(); s.setAccountId(m_account.id()); s.setShares(MyMoneyMoney::autoCalc); s.setValue(MyMoneyMoney::autoCalc); s.setMemo(i18n("Amortization")); s.setAction(MyMoneySplit::ActionAmortization); t.addSplit(s); // interest split //only add if interest is above zero if (!m_loanDetailsPage->m_interestRate->value().isZero()) { s.clearId(); s.setAccountId(m_loanSchedulePage->m_interestCategory->selectedItem()); s.setShares(MyMoneyMoney::autoCalc); s.setValue(MyMoneyMoney::autoCalc); s.setMemo(i18n("Interest")); s.setAction(MyMoneySplit::ActionInterest); t.addSplit(s); } // additional fee splits QList additionalSplits; m_loanPaymentPage->additionalFeesSplits(additionalSplits); QList::const_iterator it; MyMoneyMoney factor(moneyBorrowed() ? 1 : -1, 1); for (it = additionalSplits.constBegin(); it != additionalSplits.constEnd(); ++it) { s = (*it); s.clearId(); s.setShares(s.shares() * factor); s.setValue(s.value() * factor); t.addSplit(s); } // setup the next due date t.setPostDate(m_loanSchedulePage->firstPaymentDueDate()); m_schedule.setTransaction(t); } } return m_schedule; } MyMoneyMoney Wizard::openingBalance() const { // equity accounts don't have an opening balance if (m_accountTypePage->accountType() == Account::Equity) return MyMoneyMoney(); if (m_accountTypePage->accountType() == Account::Loan) { if (m_generalLoanInfoPage->recordAllPayments()) return MyMoneyMoney(); if (moneyBorrowed()) return -(m_generalLoanInfoPage->m_openingBalance->value()); return m_generalLoanInfoPage->m_openingBalance->value(); } return m_accountTypePage->m_openingBalance->value(); } MyMoneyPrice Wizard::conversionRate() const { if (MyMoneyFile::instance()->baseCurrency().id() == m_accountTypePage->m_currencyComboBox->security().id()) return MyMoneyPrice(MyMoneyFile::instance()->baseCurrency().id(), m_accountTypePage->m_currencyComboBox->security().id(), m_accountTypePage->m_openingDate->date(), MyMoneyMoney::ONE, i18n("User")); return MyMoneyPrice(MyMoneyFile::instance()->baseCurrency().id(), m_accountTypePage->m_currencyComboBox->security().id(), m_accountTypePage->m_openingDate->date(), m_accountTypePage->m_conversionRate->value(), i18n("User")); } bool Wizard::moneyBorrowed() const { return m_generalLoanInfoPage->m_loanDirection->currentIndex() == 0; } class InstitutionPage::Private { public: QList m_list; }; InstitutionPage::InstitutionPage(Wizard* wizard) : KInstitutionPageDecl(wizard), WizardPage(StepInstitution, this, wizard), d(new Private()) { connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); connect(m_newInstitutionButton, SIGNAL(clicked()), this, SLOT(slotNewInstitution())); connect(m_institutionComboBox, SIGNAL(activated(int)), this, SLOT(slotSelectInstitution(int))); slotLoadWidgets(); m_institutionComboBox->setCurrentItem(0); slotSelectInstitution(0); } InstitutionPage::~InstitutionPage() { delete d; } void InstitutionPage::slotLoadWidgets() { m_institutionComboBox->clear(); d->m_list.clear(); MyMoneyFile::instance()->institutionList(d->m_list); qSort(d->m_list); QList::const_iterator it_l; - m_institutionComboBox->addItem(""); + m_institutionComboBox->addItem(QString()); for (it_l = d->m_list.constBegin(); it_l != d->m_list.constEnd(); ++it_l) { m_institutionComboBox->addItem((*it_l).name()); } } void InstitutionPage::slotNewInstitution() { MyMoneyInstitution institution; emit m_wizard->createInstitution(institution); if (!institution.id().isEmpty()) { QList::const_iterator it_l; int i = 0; for (it_l = d->m_list.constBegin(); it_l != d->m_list.constEnd(); ++it_l) { if ((*it_l).id() == institution.id()) { // select the item and remember that the very first one is the empty item m_institutionComboBox->setCurrentIndex(i + 1); slotSelectInstitution(i + 1); m_accountNumber->setFocus(); break; } ++i; } } } void InstitutionPage::slotSelectInstitution(const int index) { m_accountNumber->setEnabled(index != 0); m_iban->setEnabled(index != 0); } void InstitutionPage::selectExistingInstitution(const QString& id) { for (int i = 0; i < d->m_list.length(); ++i) { if (d->m_list[i].id() == id) { m_institutionComboBox->setCurrentIndex(i + 1); slotSelectInstitution(i + 1); break; } } } const MyMoneyInstitution& InstitutionPage::institution() const { static MyMoneyInstitution emptyInstitution; if (m_institutionComboBox->currentIndex() == 0) return emptyInstitution; return d->m_list[m_institutionComboBox->currentIndex()-1]; } KMyMoneyWizardPage* InstitutionPage::nextPage() const { return m_wizard->m_accountTypePage; } AccountTypePage::AccountTypePage(Wizard* wizard) : KAccountTypePageDecl(wizard), WizardPage(StepAccount, this, wizard), m_showPriceWarning(true) { m_typeSelection->insertItem(i18n("Checking"), (int)Account::Checkings); m_typeSelection->insertItem(i18n("Savings"), (int)Account::Savings); m_typeSelection->insertItem(i18n("Credit Card"), (int)Account::CreditCard); m_typeSelection->insertItem(i18n("Cash"), (int)Account::Cash); m_typeSelection->insertItem(i18n("Loan"), (int)Account::Loan); m_typeSelection->insertItem(i18n("Investment"), (int)Account::Investment); m_typeSelection->insertItem(i18n("Asset"), (int)Account::Asset); m_typeSelection->insertItem(i18n("Liability"), (int)Account::Liability); if (KMyMoneyGlobalSettings::expertMode()) { m_typeSelection->insertItem(i18n("Equity"), (int)Account::Equity); } m_typeSelection->setCurrentItem((int)Account::Checkings); m_currencyComboBox->setSecurity(MyMoneyFile::instance()->baseCurrency()); m_mandatoryGroup->add(m_accountName); m_mandatoryGroup->add(m_conversionRate->lineedit()); m_conversionRate->setValue(MyMoneyMoney::ONE); slotUpdateCurrency(); connect(m_typeSelection, SIGNAL(itemSelected(int)), this, SLOT(slotUpdateType(int))); connect(m_currencyComboBox, SIGNAL(activated(int)), this, SLOT(slotUpdateCurrency())); connect(m_conversionRate, SIGNAL(textChanged(QString)), this, SLOT(slotUpdateConversionRate(QString))); connect(m_conversionRate, SIGNAL(valueChanged(QString)), this, SLOT(slotPriceWarning())); connect(m_onlineQuote, SIGNAL(clicked()), this, SLOT(slotGetOnlineQuote())); } void AccountTypePage::slotUpdateType(int i) { hideShowPages(static_cast(i)); m_openingBalance->setDisabled(static_cast(i) == Account::Equity); } void AccountTypePage::hideShowPages(Account accountType) const { bool hideSchedulePage = (accountType != Account::CreditCard) && (accountType != Account::Loan); bool hideLoanPage = (accountType != Account::Loan); m_wizard->setStepHidden(StepDetails, hideLoanPage); m_wizard->setStepHidden(StepPayments, hideLoanPage); m_wizard->setStepHidden(StepFees, hideLoanPage); m_wizard->setStepHidden(StepSchedule, hideSchedulePage); m_wizard->setStepHidden(StepPayout, (accountType != Account::Loan)); m_wizard->setStepHidden(StepBroker, accountType != Account::Investment); m_wizard->setStepHidden(StepParentAccount, accountType == Account::Loan); // Force an update of the steps in case the list has changed m_wizard->reselectStep(); } KMyMoneyWizardPage* AccountTypePage::nextPage() const { if (accountType() == Account::Loan) return m_wizard->m_generalLoanInfoPage; if (accountType() == Account::CreditCard) return m_wizard->m_schedulePage; if (accountType() == Account::Investment) return m_wizard->m_brokeragepage; return m_wizard->m_hierarchyPage; } void AccountTypePage::slotUpdateCurrency() { MyMoneyAccount acc; acc.setAccountType(accountType()); m_openingBalance->setPrecision(MyMoneyMoney::denomToPrec(acc.fraction(currency()))); bool show = m_currencyComboBox->security().id() != MyMoneyFile::instance()->baseCurrency().id(); m_conversionLabel->setVisible(show); m_conversionRate->setVisible(show); m_conversionExample->setVisible(show); m_onlineQuote->setVisible(show); m_conversionRate->setEnabled(show); // make sure to include/exclude in mandatoryGroup m_conversionRate->setPrecision(m_currencyComboBox->security().pricePrecision()); m_mandatoryGroup->changed(); slotUpdateConversionRate(m_conversionRate->lineedit()->text()); } void AccountTypePage::slotGetOnlineQuote() { QString id = MyMoneyFile::instance()->baseCurrency().id() + ' ' + m_currencyComboBox->security().id(); QPointer dlg = new KEquityPriceUpdateDlg(this, id); if (dlg->exec() == QDialog::Accepted) { const MyMoneyPrice &price = dlg->price(id); if (price.isValid()) { m_conversionRate->setValue(price.rate(m_currencyComboBox->security().id())); if (price.date() != m_openingDate->date()) { priceWarning(true); } } } delete dlg; } void AccountTypePage::slotPriceWarning() { priceWarning(false); } void AccountTypePage::priceWarning(bool always) { if (m_showPriceWarning || always) { KMessageBox::information(this, i18n("Please make sure to enter the correct conversion for the selected opening date. If you requested an online quote it might be provided for a different date."), i18n("Check date")); } m_showPriceWarning = false; } void AccountTypePage::slotUpdateConversionRate(const QString& txt) { m_conversionExample->setText(i18n("1 %1 equals %2", MyMoneyFile::instance()->baseCurrency().tradingSymbol(), MyMoneyMoney(txt).formatMoney(m_currencyComboBox->security().tradingSymbol(), m_currencyComboBox->security().pricePrecision()))); } bool AccountTypePage::isComplete() const { // check that the conversion rate is positive if enabled bool rc = !m_conversionRate->isVisible() || (!m_conversionRate->value().isZero() && !m_conversionRate->value().isNegative()); if (!rc) { m_wizard->m_nextButton->setToolTip(i18n("Conversion rate is not positive")); } else { rc = KMyMoneyWizardPage::isComplete(); if (!rc) { m_wizard->m_nextButton->setToolTip(i18n("No account name supplied")); } } hideShowPages(accountType()); return rc; } Account AccountTypePage::accountType() const { return static_cast(m_typeSelection->currentItem()); } const MyMoneySecurity& AccountTypePage::currency() const { return m_currencyComboBox->security(); } void AccountTypePage::setAccount(const MyMoneyAccount& acc) { if (acc.accountType() != Account::Unknown) { if (acc.accountType() == Account::AssetLoan) { m_typeSelection->setCurrentItem((int)Account::Loan); } else { m_typeSelection->setCurrentItem((int)acc.accountType()); } } m_openingDate->setDate(acc.openingDate()); m_accountName->setText(acc.name()); } const MyMoneyAccount& AccountTypePage::parentAccount() { switch (accountType()) { case Account::CreditCard: case Account::Liability: case Account::Loan: // Can be either but we return liability here return MyMoneyFile::instance()->liability(); break; case Account::Equity: return MyMoneyFile::instance()->equity(); default: break; } return MyMoneyFile::instance()->asset(); } bool AccountTypePage::allowsParentAccount() const { return accountType() != Account::Loan; } BrokeragePage::BrokeragePage(Wizard* wizard) : KBrokeragePageDecl(wizard), WizardPage(StepBroker, this, wizard) { connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); } void BrokeragePage::slotLoadWidgets() { m_brokerageCurrency->update(QString("x")); } void BrokeragePage::enterPage() { // assign the currency of the investment account to the // brokerage account if nothing else has ever been selected if (m_brokerageCurrency->security().id().isEmpty()) { m_brokerageCurrency->setSecurity(m_wizard->m_accountTypePage->m_currencyComboBox->security()); } // check if the institution relevant fields should be enabled or not bool enabled = m_wizard->m_institutionPage->m_accountNumber->isEnabled(); m_accountNumberLabel->setEnabled(enabled); m_accountNumber->setEnabled(enabled); m_ibanLabel->setEnabled(enabled); m_iban->setEnabled(enabled); } KMyMoneyWizardPage* BrokeragePage::nextPage() const { return m_wizard->m_hierarchyPage; } CreditCardSchedulePage::CreditCardSchedulePage(Wizard* wizard) : KSchedulePageDecl(wizard), WizardPage(StepSchedule, this, wizard) { m_mandatoryGroup->add(m_name); m_mandatoryGroup->add(m_payee); m_mandatoryGroup->add(m_amount->lineedit()); m_mandatoryGroup->add(m_paymentAccount); connect(m_paymentAccount, SIGNAL(itemSelected(QString)), object(), SIGNAL(completeStateChanged())); connect(m_payee, SIGNAL(itemSelected(QString)), object(), SIGNAL(completeStateChanged())); connect(m_date, SIGNAL(dateChanged(QDate)), object(), SIGNAL(completeStateChanged())); connect(m_payee, SIGNAL(createItem(QString,QString&)), wizard, SIGNAL(createPayee(QString,QString&))); m_reminderCheckBox->setChecked(true); connect(m_reminderCheckBox, SIGNAL(toggled(bool)), object(), SIGNAL(completeStateChanged())); connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); m_method->insertItem(i18n("Write check"), (int)Schedule::PaymentType::WriteChecque); #if 0 m_method->insertItem(i18n("Direct debit"), Schedule::PaymentType::DirectDebit); m_method->insertItem(i18n("Bank transfer"), Schedule::PaymentType::BankTransfer); #endif m_method->insertItem(i18n("Standing order"), (int)Schedule::PaymentType::StandingOrder); m_method->insertItem(i18n("Manual deposit"), (int)Schedule::PaymentType::ManualDeposit); m_method->insertItem(i18n("Direct deposit"), (int)Schedule::PaymentType::DirectDeposit); m_method->insertItem(i18nc("Other payment method", "Other"), (int)Schedule::PaymentType::Other); m_method->setCurrentItem((int)Schedule::PaymentType::DirectDebit); slotLoadWidgets(); } void CreditCardSchedulePage::enterPage() { if (m_name->text().isEmpty()) m_name->setText(i18n("Credit Card %1 monthly payment", m_wizard->m_accountTypePage->m_accountName->text())); } bool CreditCardSchedulePage::isComplete() const { bool rc = true; QString msg = i18n("Finish entry and create account"); if (m_reminderCheckBox->isChecked()) { msg = i18n("Finish entry and create account and schedule"); if (m_date->date() < m_wizard->m_accountTypePage->m_openingDate->date()) { rc = false; msg = i18n("Next due date is prior to opening date"); } if (m_paymentAccount->selectedItem().isEmpty()) { rc = false; msg = i18n("No account selected"); } if (m_amount->lineedit()->text().isEmpty()) { rc = false; msg = i18n("No amount for payment selected"); } if (m_payee->selectedItem().isEmpty()) { rc = false; msg = i18n("No payee for payment selected"); } if (m_name->text().isEmpty()) { rc = false; msg = i18n("No name assigned for schedule"); } } m_wizard->m_finishButton->setToolTip(msg); return rc; } void CreditCardSchedulePage::slotLoadWidgets() { AccountSet set; set.addAccountGroup(Account::Asset); set.load(m_paymentAccount->selector()); m_payee->loadPayees(MyMoneyFile::instance()->payeeList()); } KMyMoneyWizardPage* CreditCardSchedulePage::nextPage() const { return m_wizard->m_hierarchyPage; } GeneralLoanInfoPage::GeneralLoanInfoPage(Wizard* wizard) : KGeneralLoanInfoPageDecl(wizard), WizardPage(StepDetails, this, wizard), m_firstTime(true) { m_mandatoryGroup->add(m_payee); // remove the unsupported payment and compounding frequencies and setup default m_paymentFrequency->removeItem((int)Schedule::Occurrence::Once); m_paymentFrequency->removeItem((int)Schedule::Occurrence::EveryOtherYear); m_paymentFrequency->setCurrentItem((int)Schedule::Occurrence::Monthly); m_compoundFrequency->removeItem((int)Schedule::Occurrence::Once); m_compoundFrequency->removeItem((int)Schedule::Occurrence::EveryOtherYear); m_compoundFrequency->setCurrentItem((int)Schedule::Occurrence::Monthly); slotLoadWidgets(); connect(m_payee, SIGNAL(createItem(QString,QString&)), wizard, SIGNAL(createPayee(QString,QString&))); connect(m_anyPayments, SIGNAL(activated(int)), object(), SIGNAL(completeStateChanged())); connect(m_recordings, SIGNAL(activated(int)), object(), SIGNAL(completeStateChanged())); connect(m_interestType, SIGNAL(activated(int)), object(), SIGNAL(completeStateChanged())); connect(m_interestChangeDateEdit, SIGNAL(dateChanged(QDate)), object(), SIGNAL(completeStateChanged())); connect(m_openingBalance, SIGNAL(textChanged(QString)), object(), SIGNAL(completeStateChanged())); connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); } KMyMoneyWizardPage* GeneralLoanInfoPage::nextPage() const { return m_wizard->m_loanDetailsPage; } bool GeneralLoanInfoPage::recordAllPayments() const { bool rc = true; // all payments if (m_recordings->isEnabled()) { if (m_recordings->currentIndex() != 0) rc = false; } return rc; } void GeneralLoanInfoPage::enterPage() { if (m_firstTime) { // setup default dates to last of this month and one year on top QDate firstDay(QDate::currentDate().year(), QDate::currentDate().month(), 1); m_firstPaymentDate->setDate(firstDay.addMonths(1).addDays(-1)); m_interestChangeDateEdit->setDate(m_firstPaymentDate->date().addYears(1));; m_firstTime = false; } } bool GeneralLoanInfoPage::isComplete() const { m_wizard->setStepHidden(StepPayout, !m_wizard->openingBalance().isZero()); bool rc = KMyMoneyWizardPage::isComplete(); if (!rc) { m_wizard->m_nextButton->setToolTip(i18n("No payee supplied")); } // fixup availability of items on this page m_recordings->setDisabled(m_anyPayments->currentIndex() == 0); m_interestFrequencyAmountEdit->setDisabled(m_interestType->currentIndex() == 0); m_interestFrequencyUnitEdit->setDisabled(m_interestType->currentIndex() == 0); m_interestChangeDateEdit->setDisabled(m_interestType->currentIndex() == 0); m_openingBalance->setDisabled(recordAllPayments()); if (m_openingBalance->isEnabled() && m_openingBalance->lineedit()->text().length() == 0) { rc = false; m_wizard->m_nextButton->setToolTip(i18n("No opening balance supplied")); } if (rc && (m_interestType->currentIndex() != 0) && (m_interestChangeDateEdit->date() <= m_firstPaymentDate->date())) { rc = false; m_wizard->m_nextButton->setToolTip(i18n("An interest change can only happen after the first payment")); } return rc; } const MyMoneyAccount& GeneralLoanInfoPage::parentAccount() { return (m_loanDirection->currentIndex() == 0) ? MyMoneyFile::instance()->liability() : MyMoneyFile::instance()->asset(); } void GeneralLoanInfoPage::slotLoadWidgets() { m_payee->loadPayees(MyMoneyFile::instance()->payeeList()); } LoanDetailsPage::LoanDetailsPage(Wizard* wizard) : KLoanDetailsPageDecl(wizard), WizardPage(StepPayments, this, wizard), m_needCalculate(true) { // force the balloon payment to zero (default) m_balloonAmount->setValue(MyMoneyMoney()); // allow any precision for the interest rate m_interestRate->setPrecision(-1); connect(m_paymentDue, SIGNAL(activated(int)), this, SLOT(slotValuesChanged())); connect(m_termAmount, SIGNAL(valueChanged(int)), this, SLOT(slotValuesChanged())); connect(m_termUnit, SIGNAL(highlighted(int)), this, SLOT(slotValuesChanged())); connect(m_loanAmount, SIGNAL(textChanged(QString)), this, SLOT(slotValuesChanged())); connect(m_interestRate, SIGNAL(textChanged(QString)), this, SLOT(slotValuesChanged())); connect(m_paymentAmount, SIGNAL(textChanged(QString)), this, SLOT(slotValuesChanged())); connect(m_balloonAmount, SIGNAL(textChanged(QString)), this, SLOT(slotValuesChanged())); connect(m_calculateButton, SIGNAL(clicked()), this, SLOT(slotCalculate())); } void LoanDetailsPage::enterPage() { // we need to remove a bunch of entries of the payment frequencies m_termUnit->clear(); m_mandatoryGroup->clear(); if (!m_wizard->openingBalance().isZero()) { m_mandatoryGroup->add(m_loanAmount->lineedit()); if (m_loanAmount->lineedit()->text().length() == 0) { m_loanAmount->setValue(m_wizard->openingBalance().abs()); } } switch (m_wizard->m_generalLoanInfoPage->m_paymentFrequency->currentItem()) { default: m_termUnit->insertItem(i18n("Payments"), (int)Schedule::Occurrence::Once); m_termUnit->setCurrentItem((int)Schedule::Occurrence::Once); break; case Schedule::Occurrence::Monthly: m_termUnit->insertItem(i18n("Months"), (int)Schedule::Occurrence::Monthly); m_termUnit->insertItem(i18n("Years"), (int)Schedule::Occurrence::Yearly); m_termUnit->setCurrentItem((int)Schedule::Occurrence::Monthly); break; case Schedule::Occurrence::Yearly: m_termUnit->insertItem(i18n("Years"), (int)Schedule::Occurrence::Yearly); m_termUnit->setCurrentItem((int)Schedule::Occurrence::Yearly); break; } } void LoanDetailsPage::slotValuesChanged() { m_needCalculate = true; m_wizard->completeStateChanged(); } void LoanDetailsPage::slotCalculate() { MyMoneyFinancialCalculator calc; double val; int PF, CF; QString result; bool moneyBorrowed = m_wizard->moneyBorrowed(); bool moneyLend = !moneyBorrowed; // FIXME: for now, we only support interest calculation at the end of the period calc.setBep(); // FIXME: for now, we only support periodic compounding calc.setDisc(); PF = m_wizard->m_generalLoanInfoPage->m_paymentFrequency->eventsPerYear(); CF = m_wizard->m_generalLoanInfoPage->m_compoundFrequency->eventsPerYear(); if (PF == 0 || CF == 0) return; calc.setPF(PF); calc.setCF(CF); if (!m_loanAmount->lineedit()->text().isEmpty()) { val = m_loanAmount->value().abs().toDouble(); if (moneyBorrowed) val = -val; calc.setPv(val); } if (!m_interestRate->lineedit()->text().isEmpty()) { val = m_interestRate->value().abs().toDouble(); calc.setIr(val); } if (!m_paymentAmount->lineedit()->text().isEmpty()) { val = m_paymentAmount->value().abs().toDouble(); if (moneyLend) val = -val; calc.setPmt(val); } if (!m_balloonAmount->lineedit()->text().isEmpty()) { val = m_balloonAmount->value().abs().toDouble(); if (moneyLend) val = -val; calc.setFv(val); } if (m_termAmount->value() != 0) { calc.setNpp(term()); } // setup of parameters is done, now do the calculation try { if (m_loanAmount->lineedit()->text().isEmpty()) { // calculate the amount of the loan out of the other information val = calc.presentValue(); - m_loanAmount->loadText(MyMoneyMoney(static_cast(val)).abs().formatMoney("", m_wizard->precision())); + m_loanAmount->loadText(MyMoneyMoney(static_cast(val)).abs().formatMoney(QString(), m_wizard->precision())); result = i18n("KMyMoney has calculated the amount of the loan as %1.", m_loanAmount->lineedit()->text()); } else if (m_interestRate->lineedit()->text().isEmpty()) { // calculate the interest rate out of the other information val = calc.interestRate(); - m_interestRate->loadText(MyMoneyMoney(static_cast(val)).abs().formatMoney("", 3)); + m_interestRate->loadText(MyMoneyMoney(static_cast(val)).abs().formatMoney(QString(), 3)); result = i18n("KMyMoney has calculated the interest rate to %1%.", m_interestRate->lineedit()->text()); } else if (m_paymentAmount->lineedit()->text().isEmpty()) { // calculate the periodical amount of the payment out of the other information val = calc.payment(); m_paymentAmount->setValue(MyMoneyMoney(static_cast(val)).abs()); // reset payment as it might have changed due to rounding val = m_paymentAmount->value().abs().toDouble(); if (moneyLend) val = -val; calc.setPmt(val); result = i18n("KMyMoney has calculated a periodic payment of %1 to cover principal and interest.", m_paymentAmount->lineedit()->text()); val = calc.futureValue(); if ((moneyBorrowed && val < 0 && qAbs(val) >= qAbs(calc.payment())) || (moneyLend && val > 0 && qAbs(val) >= qAbs(calc.payment()))) { calc.setNpp(calc.npp() - 1); // updateTermWidgets(calc.npp()); val = calc.futureValue(); MyMoneyMoney refVal(static_cast(val)); - m_balloonAmount->loadText(refVal.abs().formatMoney("", m_wizard->precision())); + m_balloonAmount->loadText(refVal.abs().formatMoney(QString(), m_wizard->precision())); result += QString(" "); result += i18n("The number of payments has been decremented and the balloon payment has been modified to %1.", m_balloonAmount->lineedit()->text()); } else if ((moneyBorrowed && val < 0 && qAbs(val) < qAbs(calc.payment())) || (moneyLend && val > 0 && qAbs(val) < qAbs(calc.payment()))) { - m_balloonAmount->loadText(MyMoneyMoney().formatMoney("", m_wizard->precision())); + m_balloonAmount->loadText(MyMoneyMoney().formatMoney(QString(), m_wizard->precision())); } else { MyMoneyMoney refVal(static_cast(val)); - m_balloonAmount->loadText(refVal.abs().formatMoney("", m_wizard->precision())); + m_balloonAmount->loadText(refVal.abs().formatMoney(QString(), m_wizard->precision())); result += i18n("The balloon payment has been modified to %1.", m_balloonAmount->lineedit()->text()); } } else if (m_termAmount->value() == 0) { // calculate the number of payments out of the other information val = calc.numPayments(); if (val == 0) throw MYMONEYEXCEPTION("incorrect fincancial calculation"); // if the number of payments has a fractional part, then we // round it to the smallest integer and calculate the balloon payment result = i18n("KMyMoney has calculated the term of your loan as %1. ", updateTermWidgets(qFloor(val))); if (val != qFloor(val)) { calc.setNpp(qFloor(val)); val = calc.futureValue(); MyMoneyMoney refVal(static_cast(val)); - m_balloonAmount->loadText(refVal.abs().formatMoney("", m_wizard->precision())); + m_balloonAmount->loadText(refVal.abs().formatMoney(QString(), m_wizard->precision())); result += i18n("The balloon payment has been modified to %1.", m_balloonAmount->lineedit()->text()); } } else { // calculate the future value of the loan out of the other information val = calc.futureValue(); // we differentiate between the following cases: // a) the future value is greater than a payment // b) the future value is less than a payment or the loan is overpaid // c) all other cases // // a) means, we have paid more than we owed. This can't be // b) means, we paid more than we owed but the last payment is // less in value than regular payments. That means, that the // future value is to be treated as (fully payed back) // c) the loan is not payed back yet if ((moneyBorrowed && val < 0 && qAbs(val) > qAbs(calc.payment())) || (moneyLend && val > 0 && qAbs(val) > qAbs(calc.payment()))) { // case a) qDebug("Future Value is %f", val); throw MYMONEYEXCEPTION("incorrect fincancial calculation"); } else if ((moneyBorrowed && val < 0 && qAbs(val) <= qAbs(calc.payment())) || (moneyLend && val > 0 && qAbs(val) <= qAbs(calc.payment()))) { // case b) val = 0; } MyMoneyMoney refVal(static_cast(val)); - result = i18n("KMyMoney has calculated a balloon payment of %1 for this loan.", refVal.abs().formatMoney("", m_wizard->precision())); + result = i18n("KMyMoney has calculated a balloon payment of %1 for this loan.", refVal.abs().formatMoney(QString(), m_wizard->precision())); if (!m_balloonAmount->lineedit()->text().isEmpty()) { if ((m_balloonAmount->value().abs() - refVal.abs()).abs().toDouble() > 1) { throw MYMONEYEXCEPTION("incorrect fincancial calculation"); } result = i18n("KMyMoney has successfully verified your loan information."); } - m_balloonAmount->loadText(refVal.abs().formatMoney("", m_wizard->precision())); + m_balloonAmount->loadText(refVal.abs().formatMoney(QString(), m_wizard->precision())); } } catch (const MyMoneyException &) { KMessageBox::error(0, i18n("You have entered mis-matching information. Please modify " "your figures or leave one value empty " "to let KMyMoney calculate it for you"), i18n("Calculation error")); return; } result += i18n("\n\nAccept this or modify the loan information and recalculate."); KMessageBox::information(0, result, i18n("Calculation successful")); m_needCalculate = false; // now update change m_wizard->completeStateChanged(); } int LoanDetailsPage::term() const { int factor = 0; if (m_termAmount->value() != 0) { factor = 1; switch (m_termUnit->currentItem()) { case Schedule::Occurrence::Yearly: // years factor = 12; // intentional fall through case Schedule::Occurrence::Monthly: // months factor *= 30; factor *= m_termAmount->value(); // factor now is the duration in days. we divide this by the // payment frequency and get the number of payments factor /= m_wizard->m_generalLoanInfoPage->m_paymentFrequency->daysBetweenEvents(); break; default: qDebug("Unknown term unit %d in LoanDetailsPage::term(). Using payments.", (int)m_termUnit->currentItem()); // intentional fall through case Schedule::Occurrence::Once: // payments factor = m_termAmount->value(); break; } } return factor; } QString LoanDetailsPage::updateTermWidgets(const double val) { long vl = qFloor(val); QString valString; Schedule::Occurrence unit = m_termUnit->currentItem(); if ((unit == Schedule::Occurrence::Monthly) && ((vl % 12) == 0)) { vl /= 12; unit = Schedule::Occurrence::Yearly; } switch (unit) { case Schedule::Occurrence::Monthly: valString = i18np("one month", "%1 months", vl); m_termUnit->setCurrentItem((int)Schedule::Occurrence::Monthly); break; case Schedule::Occurrence::Yearly: valString = i18np("one year", "%1 years", vl); m_termUnit->setCurrentItem((int)Schedule::Occurrence::Yearly); break; default: valString = i18np("one payment", "%1 payments", vl); m_termUnit->setCurrentItem((int)Schedule::Occurrence::Once); break; } m_termAmount->setValue(vl); return valString; } bool LoanDetailsPage::isComplete() const { // bool rc = KMyMoneyWizardPage::isComplete(); int fieldCnt = 0; if (m_loanAmount->lineedit()->text().length() > 0) { fieldCnt++; } if (m_interestRate->lineedit()->text().length() > 0) { fieldCnt++; } if (m_termAmount->value() != 0) { fieldCnt++; } if (m_paymentAmount->lineedit()->text().length() > 0) { fieldCnt++; } if (m_balloonAmount->lineedit()->text().length() > 0) { fieldCnt++; } m_calculateButton->setEnabled(fieldCnt == 4 || (fieldCnt == 5 && m_needCalculate)); m_calculateButton->setAutoDefault(false); m_calculateButton->setDefault(false); if (m_needCalculate && fieldCnt == 4) { m_wizard->m_nextButton->setToolTip(i18n("Press Calculate to verify the values")); m_calculateButton->setAutoDefault(true); m_calculateButton->setDefault(true); } else if (fieldCnt != 5) { m_wizard->m_nextButton->setToolTip(i18n("Not all details supplied")); m_calculateButton->setAutoDefault(true); m_calculateButton->setDefault(true); } m_wizard->m_nextButton->setAutoDefault(!m_calculateButton->autoDefault()); m_wizard->m_nextButton->setDefault(!m_calculateButton->autoDefault()); return (fieldCnt == 5) && !m_needCalculate; } KMyMoneyWizardPage* LoanDetailsPage::nextPage() const { return m_wizard->m_loanPaymentPage; } class LoanPaymentPage::Private { public: MyMoneyAccount phonyAccount; MyMoneySplit phonySplit; MyMoneyTransaction additionalFeesTransaction; MyMoneyMoney additionalFees; }; LoanPaymentPage::LoanPaymentPage(Wizard* wizard) : KLoanPaymentPageDecl(wizard), WizardPage(StepFees, this, wizard), d(new Private) { d->phonyAccount = MyMoneyAccount(QLatin1String("Phony-ID"), MyMoneyAccount()); d->phonySplit.setAccountId(d->phonyAccount.id()); d->phonySplit.setValue(MyMoneyMoney()); d->phonySplit.setShares(MyMoneyMoney()); d->additionalFeesTransaction.addSplit(d->phonySplit); connect(m_additionalFeesButton, SIGNAL(clicked()), this, SLOT(slotAdditionalFees())); } LoanPaymentPage::~LoanPaymentPage() { delete d; } MyMoneyMoney LoanPaymentPage::basePayment() const { return m_wizard->m_loanDetailsPage->m_paymentAmount->value(); } MyMoneyMoney LoanPaymentPage::additionalFees() const { return d->additionalFees; } void LoanPaymentPage::additionalFeesSplits(QList& list) { list.clear(); QList::ConstIterator it; for (it = d->additionalFeesTransaction.splits().constBegin(); it != d->additionalFeesTransaction.splits().constEnd(); ++it) { if ((*it).accountId() != d->phonyAccount.id()) { list << (*it); } } } void LoanPaymentPage::updateAmounts() { m_additionalFees->setText(d->additionalFees.formatMoney(m_wizard->currency().tradingSymbol(), m_wizard->precision())); m_totalPayment->setText((basePayment() + d->additionalFees).formatMoney(m_wizard->currency().tradingSymbol(), m_wizard->precision())); } void LoanPaymentPage::enterPage() { const MyMoneySecurity& currency = m_wizard->currency(); m_basePayment->setText(basePayment().formatMoney(currency.tradingSymbol(), m_wizard->precision())); d->phonyAccount.setCurrencyId(currency.id()); d->additionalFeesTransaction.setCommodity(currency.id()); updateAmounts(); } void LoanPaymentPage::slotAdditionalFees() { QMap priceInfo; QPointer dlg = new KSplitTransactionDlg(d->additionalFeesTransaction, d->phonySplit, d->phonyAccount, false, !m_wizard->moneyBorrowed(), MyMoneyMoney(), priceInfo); // connect(dlg, SIGNAL(newCategory(MyMoneyAccount&)), this, SIGNAL(newCategory(MyMoneyAccount&))); if (dlg->exec() == QDialog::Accepted) { d->additionalFeesTransaction = dlg->transaction(); // sum up the additional fees QList::ConstIterator it; d->additionalFees = MyMoneyMoney(); for (it = d->additionalFeesTransaction.splits().constBegin(); it != d->additionalFeesTransaction.splits().constEnd(); ++it) { if ((*it).accountId() != d->phonyAccount.id()) { d->additionalFees += (*it).shares(); } } updateAmounts(); } delete dlg; } KMyMoneyWizardPage* LoanPaymentPage::nextPage() const { return m_wizard->m_loanSchedulePage; } LoanSchedulePage::LoanSchedulePage(Wizard* wizard) : KLoanSchedulePageDecl(wizard), WizardPage(StepSchedule, this, wizard) { m_mandatoryGroup->add(m_interestCategory->lineEdit()); m_mandatoryGroup->add(m_paymentAccount->lineEdit()); connect(m_interestCategory, SIGNAL(createItem(QString,QString&)), this, SLOT(slotCreateCategory(QString,QString&))); connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); } void LoanSchedulePage::slotCreateCategory(const QString& name, QString& id) { MyMoneyAccount acc, parent; acc.setName(name); if (m_wizard->moneyBorrowed()) parent = MyMoneyFile::instance()->expense(); else parent = MyMoneyFile::instance()->income(); emit m_wizard->createCategory(acc, parent); // return id id = acc.id(); } QDate LoanSchedulePage::firstPaymentDueDate() const { if (m_firstPaymentDueDate->isEnabled()) return m_firstPaymentDueDate->date(); return m_wizard->m_generalLoanInfoPage->m_firstPaymentDate->date(); } void LoanSchedulePage::enterPage() { m_interestCategory->setFocus(); m_firstPaymentDueDate->setDisabled(m_wizard->m_generalLoanInfoPage->recordAllPayments()); slotLoadWidgets(); } void LoanSchedulePage::slotLoadWidgets() { AccountSet set; if (m_wizard->moneyBorrowed()) set.addAccountGroup(Account::Expense); else set.addAccountGroup(Account::Income); set.load(m_interestCategory->selector()); set.clear(); set.addAccountGroup(Account::Asset); set.load(m_paymentAccount->selector()); } KMyMoneyWizardPage* LoanSchedulePage::nextPage() const { // if the balance widget of the general loan info page is enabled and // the value is not zero, then the payout already happened and we don't // aks for it. if (m_wizard->openingBalance().isZero()) return m_wizard->m_loanPayoutPage; return m_wizard->m_accountSummaryPage; } LoanPayoutPage::LoanPayoutPage(Wizard* wizard) : KLoanPayoutPageDecl(wizard), WizardPage(StepPayout, this, wizard) { m_mandatoryGroup->add(m_assetAccount->lineEdit()); m_mandatoryGroup->add(m_loanAccount->lineEdit()); KGuiItem createAssetButtenItem(i18n("&Create..."), QIcon::fromTheme(g_Icons[Icon::DocumentNew]), i18n("Create a new asset account"), i18n("If the asset account does not yet exist, press this button to create it.")); KGuiItem::assign(m_createAssetButton, createAssetButtenItem); m_createAssetButton->setToolTip(createAssetButtenItem.toolTip()); m_createAssetButton->setWhatsThis(createAssetButtenItem.whatsThis()); connect(m_createAssetButton, SIGNAL(clicked()), this, SLOT(slotCreateAssetAccount())); connect(m_noPayoutTransaction, SIGNAL(toggled(bool)), this, SLOT(slotButtonsToggled())); connect(m_refinanceLoan, SIGNAL(toggled(bool)), this, SLOT(slotButtonsToggled())); connect(MyMoneyFile::instance(), SIGNAL(dataChanged()), this, SLOT(slotLoadWidgets())); slotLoadWidgets(); } void LoanPayoutPage::slotButtonsToggled() { // we don't go directly, as the order of the emission of signals to slots is // not defined. Using a single shot timer postpones the call of m_mandatoryGroup::changed() // until the next round of the main loop so we can be sure to see all relevant changes // that happened in the meantime (eg. widgets are enabled and disabled) QTimer::singleShot(0, m_mandatoryGroup, SLOT(changed())); } void LoanPayoutPage::slotCreateAssetAccount() { MyMoneyAccount acc; acc.setAccountType(Account::Asset); acc.setOpeningDate(m_wizard->m_accountTypePage->m_openingDate->date()); emit m_wizard->createAccount(acc); if (!acc.id().isEmpty()) { m_assetAccount->setSelectedItem(acc.id()); } } void LoanPayoutPage::slotLoadWidgets() { AccountSet set; set.addAccountGroup(Account::Asset); set.load(m_assetAccount->selector()); set.clear(); set.addAccountType(Account::Loan); set.load(m_loanAccount->selector()); } void LoanPayoutPage::enterPage() { // only allow to create new asset accounts for liability loans m_createAssetButton->setEnabled(m_wizard->moneyBorrowed()); m_refinanceLoan->setEnabled(m_wizard->moneyBorrowed()); if (!m_wizard->moneyBorrowed()) { m_refinanceLoan->setChecked(false); } m_payoutDetailFrame->setDisabled(m_noPayoutTransaction->isChecked()); } KMyMoneyWizardPage* LoanPayoutPage::nextPage() const { return m_wizard->m_accountSummaryPage; } bool LoanPayoutPage::isComplete() const { return KMyMoneyWizardPage::isComplete() | m_noPayoutTransaction->isChecked(); } const QString& LoanPayoutPage::payoutAccountId() const { if (m_refinanceLoan->isChecked()) { return m_loanAccount->selectedItem(); } else { return m_assetAccount->selectedItem(); } } HierarchyFilterProxyModel::HierarchyFilterProxyModel(QObject *parent) : AccountsProxyModel(parent) { } /** * Filter the favorites accounts group. */ bool HierarchyFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { if (!source_parent.isValid()) { auto accCol = m_mdlColumns->indexOf(eAccountsModel::Column::Account); QVariant data = sourceModel()->index(source_row, accCol, source_parent).data((int)eAccountsModel::Role::ID); if (data.isValid() && data.toString() == AccountsModel::favoritesAccountId) return false; } return AccountsProxyModel::filterAcceptsRow(source_row, source_parent); } /** * Filter all but the first column. */ bool HierarchyFilterProxyModel::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const { Q_UNUSED(source_parent) if (source_column == 0) return true; return false; } HierarchyPage::HierarchyPage(Wizard* wizard) : KHierarchyPageDecl(wizard), WizardPage(StepParentAccount, this, wizard), m_filterProxyModel(nullptr) { // the proxy filter model m_filterProxyModel = new HierarchyFilterProxyModel(this); m_filterProxyModel->setHideClosedAccounts(true); m_filterProxyModel->setHideEquityAccounts(!KMyMoneyGlobalSettings::expertMode()); m_filterProxyModel->addAccountGroup(QVector {Account::Asset, Account::Liability}); auto const model = Models::instance()->accountsModel(); m_filterProxyModel->setSourceModel(model); m_filterProxyModel->setSourceColumns(model->getColumns()); m_filterProxyModel->setDynamicSortFilter(true); m_parentAccounts->setModel(m_filterProxyModel); m_parentAccounts->sortByColumn((int)eAccountsModel::Column::Account, Qt::AscendingOrder); connect(m_parentAccounts->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(parentAccountChanged())); } void HierarchyPage::enterPage() { // Ensure that the list reflects the Account Type MyMoneyAccount topAccount = m_wizard->m_accountTypePage->parentAccount(); m_filterProxyModel->clear(); m_filterProxyModel->addAccountGroup(QVector {topAccount.accountGroup()}); m_parentAccounts->expandAll(); } KMyMoneyWizardPage* HierarchyPage::nextPage() const { return m_wizard->m_accountSummaryPage; } const MyMoneyAccount& HierarchyPage::parentAccount() { QVariant data = m_parentAccounts->model()->data(m_parentAccounts->currentIndex(), (int)eAccountsModel::Role::Account); if (data.isValid()) { m_parentAccount = data.value(); } else { m_parentAccount = MyMoneyAccount(); } return m_parentAccount; } bool HierarchyPage::isComplete() const { return m_parentAccounts->currentIndex().isValid(); } void HierarchyPage::parentAccountChanged() { completeStateChanged(); } AccountSummaryPage::AccountSummaryPage(Wizard* wizard) : KAccountSummaryPageDecl(wizard), WizardPage(StepFinish, this, wizard) { } void AccountSummaryPage::enterPage() { MyMoneyAccount acc = m_wizard->account(); MyMoneySecurity sec = m_wizard->currency(); acc.fraction(sec); // assign an id to the account inside the wizard which is required for a schedule // get the schedule and clear the id again in the wizards object. MyMoneyAccount tmp(QLatin1String("Phony-ID"), acc); m_wizard->setAccount(tmp); MyMoneySchedule sch = m_wizard->schedule(); m_wizard->setAccount(acc); m_dataList->clear(); // Account data m_dataList->setFontWeight(QFont::Bold); m_dataList->append(i18n("Account information")); m_dataList->setFontWeight(QFont::Normal); m_dataList->append(i18nc("Account name", "Name: %1", acc.name())); if (!acc.isLoan()) m_dataList->append(i18n("Subaccount of %1", m_wizard->parentAccount().name())); QString accTypeText; if (acc.accountType() == Account::AssetLoan) accTypeText = i18n("Loan"); else accTypeText = m_wizard->m_accountTypePage->m_typeSelection->currentText(); m_dataList->append(i18n("Type: %1", accTypeText)); m_dataList->append(i18n("Currency: %1", m_wizard->currency().name())); m_dataList->append(i18n("Opening date: %1", QLocale().toString(acc.openingDate()))); if (m_wizard->currency().id() != MyMoneyFile::instance()->baseCurrency().id()) { - m_dataList->append(i18n("Conversion rate: %1", m_wizard->conversionRate().rate(QString()).formatMoney("", m_wizard->currency().pricePrecision()))); + m_dataList->append(i18n("Conversion rate: %1", m_wizard->conversionRate().rate(QString()).formatMoney(QString(), m_wizard->currency().pricePrecision()))); } if (!acc.isLoan() || !m_wizard->openingBalance().isZero()) m_dataList->append(i18n("Opening balance: %1", MyMoneyUtils::formatMoney(m_wizard->openingBalance(), acc, sec))); if (!m_wizard->m_institutionPage->institution().id().isEmpty()) { m_dataList->append(i18n("Institution: %1", m_wizard->m_institutionPage->institution().name())); if (!acc.number().isEmpty()) { m_dataList->append(i18n("Number: %1", acc.number())); } if (!acc.value("iban").isEmpty()) { m_dataList->append(i18n("IBAN: %1", acc.value("iban"))); } } if (acc.accountType() == Account::Investment) { if (m_wizard->m_brokeragepage->m_createBrokerageButton->isChecked()) { m_dataList->setFontWeight(QFont::Bold); m_dataList->append(i18n("Brokerage Account")); m_dataList->setFontWeight(QFont::Normal); m_dataList->append(i18nc("Account name", "Name: %1 (Brokerage)", acc.name())); m_dataList->append(i18n("Currency: %1", m_wizard->m_brokeragepage->m_brokerageCurrency->security().name())); if (m_wizard->m_brokeragepage->m_accountNumber->isEnabled() && !m_wizard->m_brokeragepage->m_accountNumber->text().isEmpty()) m_dataList->append(i18n("Number: %1", m_wizard->m_brokeragepage->m_accountNumber->text())); if (m_wizard->m_brokeragepage->m_iban->isEnabled() && !m_wizard->m_brokeragepage->m_iban->text().isEmpty()) m_dataList->append(i18n("IBAN: %1", m_wizard->m_brokeragepage->m_iban->text())); } } // Loan if (acc.isLoan()) { m_dataList->setFontWeight(QFont::Bold); m_dataList->append(i18n("Loan information")); m_dataList->setFontWeight(QFont::Normal); if (m_wizard->moneyBorrowed()) { m_dataList->append(i18n("Amount borrowed: %1", m_wizard->m_loanDetailsPage->m_loanAmount->value().formatMoney(m_wizard->currency().tradingSymbol(), m_wizard->precision()))); } else { m_dataList->append(i18n("Amount lent: %1", m_wizard->m_loanDetailsPage->m_loanAmount->value().formatMoney(m_wizard->currency().tradingSymbol(), m_wizard->precision()))); } - m_dataList->append(i18n("Interest rate: %1 %", m_wizard->m_loanDetailsPage->m_interestRate->value().formatMoney("", -1))); + m_dataList->append(i18n("Interest rate: %1 %", m_wizard->m_loanDetailsPage->m_interestRate->value().formatMoney(QString(), -1))); m_dataList->append(i18n("Interest rate is %1", m_wizard->m_generalLoanInfoPage->m_interestType->currentText())); m_dataList->append(i18n("Principal and interest: %1", MyMoneyUtils::formatMoney(m_wizard->m_loanDetailsPage->m_paymentAmount->value(), acc, sec))); m_dataList->append(i18n("Additional Fees: %1", MyMoneyUtils::formatMoney(m_wizard->m_loanPaymentPage->additionalFees(), acc, sec))); m_dataList->append(i18n("Payment frequency: %1", m_wizard->m_generalLoanInfoPage->m_paymentFrequency->currentText())); m_dataList->append(i18n("Payment account: %1", m_wizard->m_loanSchedulePage->m_paymentAccount->currentText())); if (!m_wizard->m_loanPayoutPage->m_noPayoutTransaction->isChecked() && m_wizard->openingBalance().isZero()) { m_dataList->setFontWeight(QFont::Bold); m_dataList->append(i18n("Payout information")); m_dataList->setFontWeight(QFont::Normal); if (m_wizard->m_loanPayoutPage->m_refinanceLoan->isChecked()) { m_dataList->append(i18n("Refinance: %1", m_wizard->m_loanPayoutPage->m_loanAccount->currentText())); } else { if (m_wizard->moneyBorrowed()) m_dataList->append(i18n("Transfer amount to %1", m_wizard->m_loanPayoutPage->m_assetAccount->currentText())); else m_dataList->append(i18n("Transfer amount from %1", m_wizard->m_loanPayoutPage->m_assetAccount->currentText())); } m_dataList->append(i18n("Payment date: %1 ", QLocale().toString(m_wizard->m_loanPayoutPage->m_payoutDate->date()))); } } // Schedule if (!(sch == MyMoneySchedule())) { m_dataList->setFontWeight(QFont::Bold); m_dataList->append(i18n("Schedule information")); m_dataList->setFontWeight(QFont::Normal); m_dataList->append(i18nc("Schedule name", "Name: %1", sch.name())); if (acc.accountType() == Account::CreditCard) { MyMoneyAccount paymentAccount = MyMoneyFile::instance()->account(m_wizard->m_schedulePage->m_paymentAccount->selectedItem()); m_dataList->append(i18n("Occurrence: Monthly")); m_dataList->append(i18n("Paid from %1", paymentAccount.name())); m_dataList->append(i18n("Pay to %1", m_wizard->m_schedulePage->m_payee->currentText())); m_dataList->append(i18n("Amount: %1", MyMoneyUtils::formatMoney(m_wizard->m_schedulePage->m_amount->value(), acc, sec))); m_dataList->append(i18n("First payment due on %1", QLocale().toString(sch.nextDueDate()))); m_dataList->append(i18n("Payment method: %1", m_wizard->m_schedulePage->m_method->currentText())); } if (acc.isLoan()) { m_dataList->append(i18n("Occurrence: %1", m_wizard->m_generalLoanInfoPage->m_paymentFrequency->currentText())); m_dataList->append(i18n("Amount: %1", MyMoneyUtils::formatMoney(m_wizard->m_loanPaymentPage->basePayment() + m_wizard->m_loanPaymentPage->additionalFees(), acc, sec))); m_dataList->append(i18n("First payment due on %1", QLocale().toString(m_wizard->m_loanSchedulePage->firstPaymentDueDate()))); } } } } diff --git a/kmymoney/wizards/newloanwizard/loanattributeswizardpage.cpp b/kmymoney/wizards/newloanwizard/loanattributeswizardpage.cpp index fbc6c0cd3..a9e6830a8 100644 --- a/kmymoney/wizards/newloanwizard/loanattributeswizardpage.cpp +++ b/kmymoney/wizards/newloanwizard/loanattributeswizardpage.cpp @@ -1,116 +1,117 @@ /*************************************************************************** loanattributeswizardpage - description ------------------- begin : Mon Dec 30 2013 copyright : (C) 2013 by Jeremy Whiting email : jpwhiting@kde.org ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "loanattributeswizardpage.h" // ---------------------------------------------------------------------------- // QT Includes // ---------------------------------------------------------------------------- // KDE Includes #include #include // ---------------------------------------------------------------------------- // Project Includes #include "ui_loanattributeswizardpage.h" #include "knewbankdlg.h" #include "mymoneyfile.h" +#include "mymoneyinstitution.h" #include "mymoneyexception.h" LoanAttributesWizardPage::LoanAttributesWizardPage(QWidget *parent) : QWizardPage(parent), ui(new Ui::LoanAttributesWizardPage) { ui->setupUi(this); // Register the fields with the QWizard and connect the // appropriate signals to update the "Next" button correctly registerField("institution", ui->m_qcomboboxInstitutions); connect(ui->m_qcomboboxInstitutions, SIGNAL(currentIndexChanged(int)), this, SIGNAL(completeChanged())); connect(ui->m_qbuttonNew, SIGNAL(clicked()), this, SLOT(slotNewClicked())); ui->m_qcomboboxInstitutions->clear(); // Are we forcing the user to use institutions? ui->m_qcomboboxInstitutions->addItem(i18n("(No Institution)")); try { MyMoneyFile *file = MyMoneyFile::instance(); QList list; file->institutionList(list); qSort(list); Q_FOREACH(const MyMoneyInstitution &institution, list) { ui->m_qcomboboxInstitutions->addItem(institution.name()); } } catch (const MyMoneyException &e) { qDebug("Exception in institution load: %s", qPrintable(e.what())); } } LoanAttributesWizardPage::~LoanAttributesWizardPage() { delete ui; } /** * Update the "Next" button */ bool LoanAttributesWizardPage::isComplete() const { return true; } void LoanAttributesWizardPage::initializePage() { } void LoanAttributesWizardPage::setInstitution(const QString &institutionName) { if (institutionName.isEmpty()) { ui->m_qcomboboxInstitutions->setCurrentItem(i18n("(No Institution)")); } else { ui->m_qcomboboxInstitutions->setCurrentItem(institutionName, false); } } void LoanAttributesWizardPage::slotNewClicked() { MyMoneyInstitution institution; QPointer dlg = new KNewBankDlg(institution, this); if (dlg->exec() && dlg != 0) { MyMoneyFileTransaction ft; try { MyMoneyFile *file = MyMoneyFile::instance(); institution = dlg->institution(); file->addInstitution(institution); ft.commit(); initializePage(); ui->m_qcomboboxInstitutions->setCurrentItem(institution.name(), false); } catch (const MyMoneyException &) { KMessageBox::information(this, i18n("Cannot add institution")); } } delete dlg; }