diff --git a/kmymoney/plugins/ofx/import/dialogs/konlinebankingsetupwizard.cpp b/kmymoney/plugins/ofx/import/dialogs/konlinebankingsetupwizard.cpp index 5dde04a97..b9b977e52 100644 --- a/kmymoney/plugins/ofx/import/dialogs/konlinebankingsetupwizard.cpp +++ b/kmymoney/plugins/ofx/import/dialogs/konlinebankingsetupwizard.cpp @@ -1,588 +1,590 @@ /*************************************************************************** konlinebankingsetupwizard.cpp ------------------- begin : Sat Jan 7 2006 copyright : (C) 2006 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 "konlinebankingsetupwizard.h" // ---------------------------------------------------------------------------- // QT Includes #include #include #include #include #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include #include #include #include #include #include #include // ---------------------------------------------------------------------------- // Project Includes #include "../ofxpartner.h" #include "mymoneyofxconnector.h" +#include "passwordtoggle.h" using KWallet::Wallet; class KOnlineBankingSetupWizard::Private { public: Private() : m_prevPage(-1), m_wallet(0), m_walletIsOpen(false) {} QFile m_fpTrace; QTextStream m_trace; int m_prevPage; Wallet *m_wallet; bool m_walletIsOpen; }; KOnlineBankingSetupWizard::KOnlineBankingSetupWizard(QWidget *parent): QWizard(parent), d(new Private), m_fDone(false), m_fInit(false), m_appId(0) { setupUi(this); m_applicationEdit->hide(); m_headerVersionEdit->hide(); #ifndef LIBOFX_HAVE_CLIENTUID m_editClientUid->setEnabled(false); m_clientUidLabel->setEnabled(false); #endif m_appId = new OfxAppVersion(m_applicationCombo, m_applicationEdit, ""); m_headerVersion = new OfxHeaderVersion(m_headerVersionCombo, ""); // fill the list view with banks QProgressDialog* dlg = new QProgressDialog(this); dlg->setWindowTitle(i18n("Loading banklist")); dlg->setLabelText(i18n("Getting list of banks from https://www.ofxhome.com/\nThis may take some time depending on the available bandwidth.")); dlg->setModal(true); dlg->setCancelButton(0); // force to show immediately as the call to OfxPartner::BankNames() // does not call the processEvents() loop dlg->setMinimumDuration(0); QCoreApplication::processEvents(); //set password field according to KDE preferences m_editPassword->setPasswordMode(true); + new PasswordToggle(m_editPassword); // make sure to not exceed data fields m_editUsername->setMaxLength(OFX_USERID_LENGTH-1); m_editPassword->setMaxLength(OFX_USERPASS_LENGTH-1); KListWidgetSearchLine* searchLine = new KListWidgetSearchLine(autoTab, m_listFi); vboxLayout1->insertWidget(0, searchLine); QTimer::singleShot(20, searchLine, SLOT(setFocus())); OfxPartner::setDirectory(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + ""); m_listFi->addItems(OfxPartner::BankNames()); m_fInit = true; delete dlg; checkNextButton(); connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(checkNextButton())); connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(newPage(int))); connect(m_listFi, SIGNAL(itemSelectionChanged()), this, SLOT(checkNextButton())); connect(m_listAccount, SIGNAL(itemSelectionChanged()), this, SLOT(checkNextButton())); connect(m_selectionTab, SIGNAL(currentChanged(int)), this, SLOT(checkNextButton())); connect(m_fid, SIGNAL(userTextChanged(QString)), this, SLOT(checkNextButton())); connect(m_bankName, SIGNAL(userTextChanged(QString)), this, SLOT(checkNextButton())); connect(m_url, SIGNAL(textChanged(QString)), this, SLOT(checkNextButton())); connect(m_editUsername, SIGNAL(userTextChanged(QString)), this, SLOT(checkNextButton())); connect(m_editPassword, SIGNAL(userTextChanged(QString)), this, SLOT(checkNextButton())); connect(m_applicationEdit, SIGNAL(userTextChanged(QString)), this, SLOT(checkNextButton())); connect(m_applicationCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(applicationSelectionChanged())); // setup text on buttons setButtonText(QWizard::NextButton, i18nc("Go to next page of the wizard", "&Next")); setButtonText(QWizard::BackButton, KStandardGuiItem::back().text()); // setup icons button(QWizard::FinishButton)->setIcon(KStandardGuiItem::ok().icon()); button(QWizard::CancelButton)->setIcon(KStandardGuiItem::cancel().icon()); button(QWizard::NextButton)->setIcon(KStandardGuiItem::forward(KStandardGuiItem::UseRTL).icon()); button(QWizard::BackButton)->setIcon(KStandardGuiItem::back(KStandardGuiItem::UseRTL).icon()); m_problemMessages->setHidden(true); m_problemMessages->setWordWrap(true); } KOnlineBankingSetupWizard::~KOnlineBankingSetupWizard() { delete m_appId; delete d; } void KOnlineBankingSetupWizard::applicationSelectionChanged() { m_applicationEdit->setVisible(m_appId->appId().endsWith(':')); checkNextButton(); } void KOnlineBankingSetupWizard::walletOpened(bool ok) { if (ok && (d->m_wallet->hasFolder(KWallet::Wallet::PasswordFolder()) || d->m_wallet->createFolder(KWallet::Wallet::PasswordFolder())) && d->m_wallet->setFolder(KWallet::Wallet::PasswordFolder())) { d->m_walletIsOpen = true; } else { qDebug("Wallet was not opened"); } m_storePassword->setEnabled(d->m_walletIsOpen); } void KOnlineBankingSetupWizard::checkNextButton() { bool enableButton = false; switch (currentId()) { case 0: if (m_selectionTab->currentIndex() == 0) { enableButton = (m_listFi->currentItem() != 0) && m_listFi->currentItem()->isSelected(); } else { enableButton = !(m_url->url().isEmpty() || m_bankName->text().isEmpty()); } break; case 1: enableButton = !(m_editUsername->text().isEmpty() || m_editPassword->text().isEmpty() || !m_appId->isValid()); break; case 2: enableButton = (m_listAccount->currentItem() != 0) && m_listAccount->currentItem()->isSelected(); break; } button(QWizard::NextButton)->setEnabled(enableButton); } void KOnlineBankingSetupWizard::newPage(int id) { QWidget* focus = 0; m_problemMessages->setHidden(true); bool ok = true; if ((id - d->m_prevPage) == 1) { // one page forward? switch (d->m_prevPage) { case 0: ok = finishFiPage(); // open the KDE wallet if not already opened if (ok && !d->m_wallet) { d->m_wallet = Wallet::openWallet(Wallet::NetworkWallet(), winId(), Wallet::Asynchronous); connect(d->m_wallet, SIGNAL(walletOpened(bool)), SLOT(walletOpened(bool))); } focus = m_editUsername; break; case 1: ok = finishLoginPage(); focus = m_listAccount; break; case 2: m_fDone = ok = finishAccountPage(); break; } if (ok) { if (focus) { focus->setFocus(); } } else { // force to go back to prev page back(); } } else { // going backwards, we're never done m_fDone = false; } button(QWizard::FinishButton)->setEnabled(m_fDone); // hide cancel and back button on last page button(QWizard::CancelButton)->setVisible(!m_fDone); button(QWizard::BackButton)->setVisible(!m_fDone); if (ok) d->m_prevPage = id; } bool KOnlineBankingSetupWizard::finishFiPage() { bool result = false; m_bankInfo.clear(); OfxHomeServiceInfo info; if (m_selectionTab->currentIndex() == 0) { // Get the fipids for the selected bank QListWidgetItem* item = m_listFi->currentItem(); if (item && item->isSelected()) { QString bank = item->text(); m_textDetails->clear(); m_textDetails->append(QString("

Details for %1:

").arg(bank)); QStringList fipids = OfxPartner::FipidForBank(bank); QStringList::const_iterator it_fipid = fipids.constBegin(); while (it_fipid != fipids.constEnd()) { // For each fipid, get the connection details info = OfxPartner::ServiceInfo(*it_fipid); // Print them to the text browser QString message = QString("

Fipid: %1
").arg(*it_fipid); // If the bank supports retrieving statements if (info.ofxInfo.accountlist) { m_bankInfo.push_back(info.ofxInfo); message += QString("URL: %1
Org: %2
Fid: %3
").arg(info.ofxInfo.url, info.ofxInfo.org, info.ofxInfo.fid); if (info.ofxInfo.statements) message += i18n("Supports online statements
"); if (info.ofxInfo.investments) message += i18n("Supports investments
"); if (info.ofxInfo.billpay) message += i18n("Supports bill payment (but not supported by KMyMoney yet)
"); QString problemMessage; if (!info.ofxValidated) problemMessage += i18n("OFX host failed. Last successful access was on '%1'. ", info.lastOfxValidated); if (!info.sslValidated) problemMessage += i18n("Certificate verification of OFX host failed. Last successful verification was on '%1'.", info.lastSslValidated); if (!problemMessage.isEmpty()) { m_problemMessages->setText(problemMessage); m_problemMessages->animatedShow(); } } else { message += i18n("Does not support online banking"); } message += "

"; m_textDetails->append(message); ++it_fipid; } result = true; } else // error! No current item KMessageBox::sorry(this, i18n("Please choose a bank.")); } else { // manual entry of values if (m_fid->text().isEmpty() || m_url->url().isEmpty() || m_bankName->text().isEmpty()) { KMessageBox::sorry(this, i18n("Please fill all fields with values.")); } m_textDetails->clear(); m_textDetails->append(i18n("

Details for %1:

", m_bankName->text())); memset(&info.ofxInfo, 0, sizeof(OfxFiServiceInfo)); strncpy(info.ofxInfo.fid, m_fid->text().toLatin1(), OFX_FID_LENGTH - 1); strncpy(info.ofxInfo.org, m_bankName->text().toLatin1(), OFX_ORG_LENGTH - 1); strncpy(info.ofxInfo.url, m_url->url().url().toLatin1(), OFX_URL_LENGTH - 1); info.ofxInfo.accountlist = 1; info.ofxInfo.statements = 1; info.ofxInfo.billpay = 1; info.ofxInfo.investments = 1; m_bankInfo.push_back(info.ofxInfo); QString message; message += QString("

URL: %1
Org: %2
Fid: %3
").arg(info.ofxInfo.url, info.ofxInfo.org, info.ofxInfo.fid); if (info.ofxInfo.statements) message += i18n("Supports online statements
"); if (info.ofxInfo.investments) message += i18n("Supports investments
"); if (info.ofxInfo.billpay) message += i18n("Supports bill payment (but not supported by KMyMoney yet)
"); message += "

"; m_textDetails->append(message); result = true; } // make sure to display the beginning of the collected information m_textDetails->moveCursor(QTextCursor::Start); return result; } bool KOnlineBankingSetupWizard::finishLoginPage() { bool result = true; QString username = m_editUsername->text(); QString password = m_editPassword->text(); QString clientUid = m_editClientUid->text(); m_listAccount->clear(); // Process an account request for each fipid m_it_info = m_bankInfo.constBegin(); while (m_it_info != m_bankInfo.constEnd()) { OfxFiLogin fi; memset(&fi, 0, sizeof(OfxFiLogin)); Q_ASSERT(sizeof(fi.fid) == sizeof((*m_it_info).fid)); Q_ASSERT(sizeof(fi.org) == sizeof((*m_it_info).org)); memcpy(fi.fid, (*m_it_info).fid, OFX_FID_LENGTH - 1); memcpy(fi.org, (*m_it_info).org, OFX_ORG_LENGTH - 1); strncpy(fi.userid, username.toLatin1().left(OFX_USERID_LENGTH - 1), OFX_USERID_LENGTH - 1); strncpy(fi.userpass, password.toLatin1(), OFX_USERPASS_LENGTH - 1); #ifdef LIBOFX_HAVE_CLIENTUID strncpy(fi.clientuid, clientUid.toLatin1(), OFX_CLIENTUID_LENGTH - 1); #endif // pretend we're Quicken 2008 // http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-intuit-products/ // http://ofxblog.wordpress.com/2007/06/06/ofx-appid-and-appver-for-microsoft-money/ QString appId = m_appId->appId(); QRegExp exp("(.*):(.*)"); if (exp.indexIn(appId) != -1) { strncpy(fi.appid, exp.cap(1).toLatin1(), OFX_APPID_LENGTH - 1); if (exp.cap(2).isEmpty()) { strncpy(fi.appver, m_applicationEdit->text().toLatin1(), OFX_APPVER_LENGTH - 1); } else { strncpy(fi.appver, exp.cap(2).toLatin1(), OFX_APPVER_LENGTH - 1); } } else { strncpy(fi.appid, "QWIN", OFX_APPID_LENGTH - 1); strncpy(fi.appver, "1700", OFX_APPVER_LENGTH - 1); } QString hver = m_headerVersion->headerVersion(); strncpy(fi.header_version, hver.toLatin1(), OFX_HEADERVERSION_LENGTH - 1); QUrl filename(QString("file://%1response.ofx").arg(QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/'))); QByteArray req(libofx_request_accountinfo(&fi)); // because the event loop is running while the request is performed disable the back button // (this function is not reentrant so the application might crash when back/next are used) QAbstractButton *backButton = button(QWizard::BackButton); bool backButtonState = backButton->isEnabled(); backButton->setEnabled(false); OfxHttpRequest(QString("POST"), QUrl((*m_it_info).url), req, QMap(), filename, false); backButton->setEnabled(backButtonState); LibofxContextPtr ctx = libofx_get_new_context(); Q_CHECK_PTR(ctx); ofx_set_account_cb(ctx, ofxAccountCallback, this); ofx_set_status_cb(ctx, ofxStatusCallback, this); // Add resulting accounts to the account list libofx_proc_file(ctx, filename.toLocalFile().toLatin1(), AUTODETECT); libofx_free_context(ctx); ++m_it_info; } if (! m_listAccount->topLevelItem(0)) { KMessageBox::sorry(this, i18n("No suitable accounts were found at this bank.")); result = false; } else { m_listAccount->resizeColumnToContents(0); m_listAccount->resizeColumnToContents(1); m_listAccount->resizeColumnToContents(2); m_listAccount->resizeColumnToContents(3); } return result; } bool KOnlineBankingSetupWizard::finishAccountPage() { bool result = true; if (! m_listAccount->currentItem()) { KMessageBox::sorry(this, i18n("Please choose an account")); result = false; } return result; } int KOnlineBankingSetupWizard::ofxAccountCallback(struct OfxAccountData data, void * pv) { KOnlineBankingSetupWizard* pthis = reinterpret_cast(pv); // Put the account info in the view MyMoneyKeyValueContainer kvps; if (data.account_type_valid) { QString type; switch (data.account_type) { case OfxAccountData::OFX_CHECKING: /**< A standard checking account */ type = "CHECKING"; break; case OfxAccountData::OFX_SAVINGS: /**< A standard savings account */ type = "SAVINGS"; break; case OfxAccountData::OFX_MONEYMRKT: /**< A money market account */ type = "MONEY MARKET"; break; case OfxAccountData::OFX_CREDITLINE: /**< A line of credit */ type = "CREDIT LINE"; break; case OfxAccountData::OFX_CMA: /**< Cash Management Account */ type = "CMA"; break; case OfxAccountData::OFX_CREDITCARD: /**< A credit card account */ type = "CREDIT CARD"; break; case OfxAccountData::OFX_INVESTMENT: /**< An investment account */ type = "INVESTMENT"; break; default: break; } kvps.setValue("type", type); } if (data.bank_id_valid) kvps.setValue("bankid", data.bank_id); if (data.broker_id_valid) kvps.setValue("bankid", data.broker_id); if (data.branch_id_valid) kvps.setValue("branchid", data.branch_id); if (data.account_number_valid) kvps.setValue("accountid", data.account_number); if (data.account_id_valid) kvps.setValue("uniqueId", data.account_id); kvps.setValue("username", pthis->m_editUsername->text()); kvps.setValue("password", pthis->m_editPassword->text()); #ifdef LIBOFX_HAVE_CLIENTUID kvps.setValue("clientUid", pthis->m_editClientUid->text()); #endif kvps.setValue("url", (*(pthis->m_it_info)).url); kvps.setValue("fid", (*(pthis->m_it_info)).fid); kvps.setValue("org", (*(pthis->m_it_info)).org); kvps.setValue("fipid", ""); QListWidgetItem* item = pthis->m_listFi->currentItem(); if (item) kvps.setValue("bankname", item->text()); // I removed the bankid here, because for some users it // was not possible to setup the automatic account matching // because the bankid was left empty here as well during // the statement download. In case we don't have it, we // simply use it blank. (ipwizard 2009-06-21) if (/* !kvps.value("bankid").isEmpty() && */ !kvps.value("uniqueId").isEmpty()) { kvps.setValue("kmmofx-acc-ref", QString("%1-%2").arg(kvps.value("bankid"), kvps.value("uniqueId"))); } else { qDebug("Cannot setup kmmofx-acc-ref for '%s'", qPrintable(kvps.value("bankname"))); } kvps.setValue("protocol", "OFX"); new ListViewItem(pthis->m_listAccount, kvps); return 0; } int KOnlineBankingSetupWizard::ofxStatusCallback(struct OfxStatusData data, void * pv) { KOnlineBankingSetupWizard* pthis = reinterpret_cast(pv); QString message; if (data.code_valid) { message += QString("#%1 %2: \"%3\"\n").arg(data.code).arg(data.name, data.description); } if (data.server_message_valid) { message += i18n("Server message: %1\n", data.server_message); } if (data.severity_valid) { switch (data.severity) { case OfxStatusData::INFO : break; case OfxStatusData::WARN : KMessageBox::detailedError(pthis, i18n("Your bank returned warnings when signing on"), i18nc("Warning 'message'", "WARNING %1", message)); break; case OfxStatusData::ERROR : KMessageBox::detailedError(pthis, i18n("Error signing onto your bank"), i18n("ERROR %1", message)); break; default: break; } } return 0; } bool KOnlineBankingSetupWizard::chosenSettings(MyMoneyKeyValueContainer& settings) { bool result = false;; if (m_fDone) { QTreeWidgetItem* qitem = m_listAccount->currentItem(); ListViewItem* item = dynamic_cast(qitem); if (item && item->isSelected()) { settings = *item; settings.deletePair("appId"); settings.deletePair("kmmofx-headerVersion"); QString appId = m_appId->appId(); if (!appId.isEmpty()) { if (appId.endsWith(':')) { appId += m_applicationEdit->text(); } settings.setValue("appId", appId); } QString hVer = m_headerVersion->headerVersion(); if (!hVer.isEmpty()) settings.setValue("kmmofx-headerVersion", hVer); if (m_storePassword->isChecked()) { if (d->m_walletIsOpen) { QString key = OFX_PASSWORD_KEY(settings.value("url"), settings.value("uniqueId")); d->m_wallet->writePassword(key, settings.value("password")); settings.deletePair("password"); } } else { settings.deletePair("password"); } result = true; } } return result; } KOnlineBankingSetupWizard::ListViewItem::ListViewItem(QTreeWidget* parent, const MyMoneyKeyValueContainer& kvps): MyMoneyKeyValueContainer(kvps), QTreeWidgetItem(parent) { setText(0, value("accountid")); setText(1, value("type")); setText(2, value("bankid")); setText(3, value("branchid")); } diff --git a/kmymoney/plugins/sql/kselectdatabasedlg.cpp b/kmymoney/plugins/sql/kselectdatabasedlg.cpp index e1ba5df96..65a054622 100644 --- a/kmymoney/plugins/sql/kselectdatabasedlg.cpp +++ b/kmymoney/plugins/sql/kselectdatabasedlg.cpp @@ -1,256 +1,236 @@ /*************************************************************************** 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" // ---------------------------------------------------------------------------- // QT Includes #include #include // ---------------------------------------------------------------------------- // KDE Includes #include #include // ---------------------------------------------------------------------------- // Project Includes #include "ui_kselectdatabasedlg.h" #include "kguiutils.h" #include "mymoneystoragesql.h" #include "mymoneydbdriver.h" #include "misc/platformtools.h" - +#include "passwordtoggle.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); - m_toggleEchoModeAction = m_widget->textPassword->addAction(QIcon::fromTheme(QStringLiteral("visibility")), QLineEdit::TrailingPosition); - m_toggleEchoModeAction->setVisible(false); - m_toggleEchoModeAction->setToolTip(i18n("Change the visibility of the password")); - connect(m_widget->textPassword, &QLineEdit::textChanged, this, &KSelectDatabaseDlg::showToggleEchoModeAction); - connect(m_toggleEchoModeAction, &QAction::triggered, this, &KSelectDatabaseDlg::toggleEchoMode); + new PasswordToggle(m_widget->textPassword); } KSelectDatabaseDlg::~KSelectDatabaseDlg() { } -void KSelectDatabaseDlg::showToggleEchoModeAction(const QString& text) -{ - m_toggleEchoModeAction->setVisible(!text.isEmpty()); -} - -void KSelectDatabaseDlg::toggleEchoMode() -{ - if (m_widget->textPassword->echoMode() == QLineEdit::Password) { - m_widget->textPassword->setEchoMode(QLineEdit::Normal); - m_toggleEchoModeAction->setIcon(QIcon::fromTheme(QStringLiteral("hint"))); - } else if (m_widget->textPassword->echoMode() == QLineEdit::Normal) { - m_widget->textPassword->setEchoMode(QLineEdit::Password); - m_toggleEchoModeAction->setIcon(QIcon::fromTheme(QStringLiteral("visibility"))); - } -} - 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, 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()); // set path which begins with a separator slash that will be removed when retrieved from path() if (m_sqliteSelected) url.setPath('/' + m_widget->urlSqlite->url().toLocalFile()); 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 requires 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/plugins/sql/kselectdatabasedlg.h b/kmymoney/plugins/sql/kselectdatabasedlg.h index 545f230f6..27824d8c9 100644 --- a/kmymoney/plugins/sql/kselectdatabasedlg.h +++ b/kmymoney/plugins/sql/kselectdatabasedlg.h @@ -1,80 +1,76 @@ /*************************************************************************** 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 +#include // ---------------------------------------------------------------------------- // Project Includes namespace Ui { class KSelectDatabaseDlg; } class KMandatoryFieldGroup; class QAction; class KSelectDatabaseDlg : public QDialog { Q_OBJECT public: 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() override; public Q_SLOTS: void slotDriverSelected(int idx); void slotHelp(); -private Q_SLOTS: - void showToggleEchoModeAction(const QString &text); - void toggleEchoMode(); - private: Ui::KSelectDatabaseDlg* m_widget; int m_mode; QUrl m_url; KMandatoryFieldGroup* m_requiredFields; bool m_sqliteSelected; - QAction *m_toggleEchoModeAction; }; #endif diff --git a/kmymoney/widgets/CMakeLists.txt b/kmymoney/widgets/CMakeLists.txt index 99a78776b..f2d986319 100644 --- a/kmymoney/widgets/CMakeLists.txt +++ b/kmymoney/widgets/CMakeLists.txt @@ -1,266 +1,267 @@ ########### create links ############### set(kmymoney_STAT_HEADERS kaccounttemplateselector.h kguiutils.h kmymoneyaccountcombo.h kmymoneyaccountcompletion.h kmymoneyaccountselector.h kmymoneycategory.h kmymoneycombo.h kmymoneymvccombo.h kmymoneycompletion.h kmymoneycurrencyselector.h kmymoneydateinput.h kmymoneylineedit.h kmymoneyselector.h kmymoneytitlelabel.h register.h registeritem.h groupmarker.h fancydategroupmarker.h scheduledtransaction.h selectedtransaction.h selectedtransactions.h stdtransactiondownloaded.h stdtransactionmatched.h transactioneditorcontainer.h transactionform.h transaction.h investtransaction.h stdtransaction.h transactionsortoption.h kmymoneyvalidationfeedback.h onlinejobmessagesview.h kmymoneydateedit.h amountedit.h amountvalidator.h creditdebithelper.h ) ########### Shared widget library ########### set(kmm_widgets_sources kmymoneydateinput.cpp kmymoneyvalidationfeedback.cpp styleditemdelegateforwarder.cpp kmymoneylineedit.cpp kmymoneytextedit.cpp kmymoneytextedithighlighter.cpp kmymoneymvccombo.cpp kmymoneygeneralcombo.cpp kmymoneyactivitycombo.cpp kmymoneycashflowcombo.cpp kmymoneyfrequencycombo.cpp kmymoneyoccurrencecombo.cpp kmymoneyoccurrenceperiodcombo.cpp kmymoneypayeecombo.cpp kmymoneyperiodcombo.cpp kmymoneyreconcilecombo.cpp kmymoneytagcombo.cpp kmymoneyaccountselector.cpp ktagcontainer.cpp ktaglabel.cpp kmymoneyselector.cpp kmymoneycalculator.cpp ktreewidgetfilterlinewidget.cpp kguiutils.cpp onlinejobmessagesview.cpp kmymoneydateedit.cpp kmymoneymoneyvalidator.cpp amountedit.cpp amountvalidator.cpp creditdebithelper.cpp daterangedlg.cpp ktransactionfilter.cpp kmymoneyaccounttreeview.cpp accountsviewproxymodel.cpp budgetviewproxymodel.cpp kmymoneyviewbase.cpp kmymoneyaccountsviewbase.cpp + passwordtoggle.cpp ) set(nationalAccountWidget_SOURCES ./payeeidentifier/nationalaccount/nationalaccountedit.cpp ./payeeidentifier/nationalaccount/nationalaccountdelegate.cpp ) set(nationalAccountWidget_HEADERS ./payeeidentifier/nationalaccount/nationalaccountdelegate.h ./payeeidentifier/nationalaccount/nationalaccountedit.h ) set(IBANBICWidget_SOURCES ./payeeidentifier/ibanbic/kibanlineedit.cpp ./payeeidentifier/ibanbic/kbicedit.cpp ./payeeidentifier/ibanbic/ibanvalidator.cpp ./payeeidentifier/ibanbic/bicvalidator.cpp ./payeeidentifier/ibanbic/ibanbicitemdelegate.cpp ./payeeidentifier/ibanbic/ibanbicitemedit.cpp ) set(IBANBICWidget_HEADERS ./payeeidentifier/ibanbic/kibanlineedit.h ./payeeidentifier/ibanbic/kbicedit.h ./payeeidentifier/ibanbic/ibanvalidator.h ./payeeidentifier/ibanbic/bicvalidator.h ./payeeidentifier/ibanbic/ibanbicitemdelegate.h ) list(APPEND kmm_widgets_sources ${nationalAccountWidget_SOURCES}) list(APPEND kmymoney_STAT_HEADERS ${nationalAccountWidget_HEADERS}) list(APPEND kmm_widgets_sources ${IBANBICWidget_SOURCES}) list(APPEND kmymoney_STAT_HEADERS ${IBANBICWidget_HEADERS}) ki18n_wrap_ui(kmm_widgets_sources kmymoneyvalidationfeedback.ui onlinejobmessagesview.ui daterangedlg.ui ktransactionfilter.ui ./payeeidentifier/nationalaccount/nationalaccountedit.ui ./payeeidentifier/ibanbic/ibanbicitemedit.ui ) add_library(kmm_widgets SHARED ${kmm_widgets_sources}) target_link_libraries(kmm_widgets PUBLIC kmm_settings KF5::TextWidgets KF5::KIOWidgets KF5::Completion KF5::Notifications KF5::ItemViews KF5::I18n Qt5::Gui Qt5::Core Alkimia::alkimia kmm_mymoney kmm_models kmm_plugin ) set_target_properties(kmm_widgets PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR} COMPILE_FLAGS "-DKMM_BUILD_WIDGETS_LIB" ) generate_export_header(kmm_widgets) install(TARGETS kmm_widgets ${INSTALL_TARGETS_DEFAULT_ARGS} ) ########### Basic Widget Library (kmymoney_base) STATIC ################# # Common sources for libkmymoney.so and libwidgets.a that do not # contain the KMM_DESIGNER flag set(_uncritial_common_sources kmymoneyaccountcombo.cpp kmymoneycombo.cpp kmymoneycompletion.cpp kmymoneytitlelabel.cpp kmymoneydateedit.cpp kpricetreeitem.cpp registeritem.cpp registerfilter.cpp scheduledtransaction.cpp selectedtransaction.cpp selectedtransactions.cpp stdtransactiondownloaded.cpp stdtransactionmatched.cpp transactionform.cpp tabbar.cpp transactionformitemdelegate.cpp transactionsortoption.cpp ) # sources that contain the KMM_DESIGNER flag set (_critial_common_sources kaccounttemplateselector.cpp kmymoneycurrencyselector.cpp kmymoneyaccountcompletion.cpp kmymoneycategory.cpp groupmarker.cpp groupmarkers.cpp fancydategroupmarker.cpp fancydategroupmarkers.cpp register.cpp itemptrvector.cpp qwidgetcontainer.cpp registeritemdelegate.cpp transaction.cpp stdtransaction.cpp investtransaction.cpp transactioneditorcontainer.cpp ) set (kmymoney_base_UI transactionsortoption.ui kaccounttemplateselector.ui ) ki18n_wrap_ui(kmymoney_base_ui_srcs ${kmymoney_base_UI}) set(_uncritial_common_sources ${_uncritial_common_sources} ${kmymoney_base_ui_srcs}) # in order to use add_dependencies, we need to add this custom target # for all generated header files. # (see http://www.vtk.org/Wiki/CMake_FAQ#How_can_I_add_a_dependency_to_a_source_file_which_is_generated_in_a_subdirectory.3F ) add_custom_target(generate_base_ui_srcs DEPENDS ${kmymoney_base_ui_srcs}) # We can compile the uncritical sources without KMM_DESIGNER flags add_library(kmymoney_base STATIC ${_uncritial_common_sources}) # TODO: fix dependencies target_link_libraries(kmymoney_base KF5::XmlGui KF5::TextWidgets KF5::IconThemes KF5::I18n KF5::ConfigWidgets KF5::ConfigCore KF5::Completion KF5::Service Qt5::Gui Qt5::Widgets Qt5::Xml kmm_settings Alkimia::alkimia) add_dependencies(kmymoney_base kmm_settings) ########### QtDesigner Widget Library (kmymoneywidgets) ################# # we never link against this library, # but it is needed for uic and QtDesigner if( USE_QT_DESIGNER ) set(kmymoneywidgets_PART_SRCS ${CMAKE_CURRENT_BINARY_DIR}/kmymoneywidgets.cpp) kde4_add_widget_files(kmymoneywidgets_PART_SRCS kmymoney.widgets) set(kmymoneywidgets_PART_SRCS ${_critial_common_sources} ${kmymoneywidgets_PART_SRCS}) add_library(kmymoneywidgets MODULE ${kmymoneywidgets_PART_SRCS}) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # The option -DKMM_DESIGNER will leave away any code that breaks uic. set_target_properties(kmymoneywidgets PROPERTIES COMPILE_FLAGS "-DKMM_DESIGNER") # The qt-designer widget library shouldn't need to link against the # dialogs and converter libraries. If a widget references something # from one of these libraries it is most likely due to code that needs # to be excluded with a KMM_DESIGNER ifndef. target_link_libraries(kmymoneywidgets kmymoney_base kmm_mymoney kmymoney_common kmm_settings models) install(TARGETS kmymoneywidgets DESTINATION ${QT_PLUGINS_DIR}/designer ) endif( USE_QT_DESIGNER ) ########### Widget Library (widgets) STATIC ################# set(libwidgets_a_SOURCES ${_critial_common_sources} kmymoneybriefschedule.cpp registersearchline.cpp transactioneditorcontainer.cpp ) set(libwidgets_a_UI kmymoneybriefschedule.ui ) # using uic on the above UI files DEPENDS on libkmymoney.so. If uic # does not find libkmymoney.so, gcc will fail compiling # kmymoneyreportconfigtab2decl.cpp and throw errors like "invalid use # of undefined type `struct KMyMoneyGeneralCombo'" ki18n_wrap_ui(widgets_ui_srcs ${libwidgets_a_UI}) add_custom_target(generate_widgets_ui_srcs DEPENDS ${widgets_ui_srcs}) add_library(widgets STATIC ${libwidgets_a_SOURCES} ${widgets_ui_srcs} ) target_link_libraries(widgets KF5::XmlGui kmymoney_base) add_dependencies(widgets kmm_settings) ########### install files ############### install(FILES ${kmymoney_STAT_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/kmm_widgets_export.h DESTINATION ${INCLUDE_INSTALL_DIR}/kmymoney COMPONENT Devel) ############## tests #################### if(BUILD_TESTING) add_subdirectory(tests) endif() diff --git a/kmymoney/widgets/passwordtoggle.cpp b/kmymoney/widgets/passwordtoggle.cpp new file mode 100644 index 000000000..bbe18b956 --- /dev/null +++ b/kmymoney/widgets/passwordtoggle.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2019 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. + * + * 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 "passwordtoggle.h" + +// ---------------------------------------------------------------------------- +// QT Includes + +#include +#include + +// ---------------------------------------------------------------------------- +// KDE Includes + +#include + +PasswordToggle::PasswordToggle(QLineEdit* parent) + : QObject(parent) + , m_lineEdit(parent) +{ + m_toggleAction = m_lineEdit->addAction(QIcon::fromTheme(QStringLiteral("visibility")), QLineEdit::TrailingPosition); + m_toggleAction->setVisible(false); + m_toggleAction->setToolTip(i18n("Change the visibility of the password")); + connect(m_lineEdit, &QLineEdit::textChanged, this, &PasswordToggle::toggleEchoModeAction); + connect(m_toggleAction, &QAction::triggered, this, &PasswordToggle::toggleEchoMode); +} + +void PasswordToggle::toggleEchoModeAction(const QString& text) +{ + m_toggleAction->setVisible(!text.isEmpty()); +} + +void PasswordToggle::toggleEchoMode() +{ + if (m_lineEdit->echoMode() == QLineEdit::Password) { + m_lineEdit->setEchoMode(QLineEdit::Normal); + m_toggleAction->setIcon(QIcon::fromTheme(QStringLiteral("hint"))); + } else if (m_lineEdit->echoMode() == QLineEdit::Normal) { + m_lineEdit->setEchoMode(QLineEdit::Password); + m_toggleAction->setIcon(QIcon::fromTheme(QStringLiteral("visibility"))); + } +} + diff --git a/kmymoney/widgets/passwordtoggle.h b/kmymoney/widgets/passwordtoggle.h new file mode 100644 index 000000000..8b432276f --- /dev/null +++ b/kmymoney/widgets/passwordtoggle.h @@ -0,0 +1,52 @@ +/* + * Copyright 2019 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. + * + * 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 PASSWORDTOGGLE_H +#define PASSWORDTOGGLE_H + +#include "kmm_widgets_export.h" + +// ---------------------------------------------------------------------------- +// QT Includes + +#include + +// ---------------------------------------------------------------------------- +// KDE Includes + +// ---------------------------------------------------------------------------- +// Project Includes + +class QLineEdit; +class QAction; + +class KMM_WIDGETS_EXPORT PasswordToggle : public QObject +{ + Q_OBJECT +public: + explicit PasswordToggle(QLineEdit* parent); + +protected Q_SLOTS: + void toggleEchoModeAction(const QString& text); + void toggleEchoMode(); +private: + QLineEdit* m_lineEdit; + QAction* m_toggleAction; +}; + + +#endif // PASSWORDTOGGLE_H