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

0001 /*
0002     SPDX-FileCopyrightText: 2000-2002 Michael Edwardes <mte@users.sourceforge.net>
0003     SPDX-FileCopyrightText: 2017 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "knewinstitutiondlg.h"
0008 
0009 // ----------------------------------------------------------------------------
0010 // QT Includes
0011 
0012 #include <QPushButton>
0013 #include <QTemporaryFile>
0014 #include <QTimer>
0015 #include <QDesktopServices>
0016 #include <QRegularExpression>
0017 
0018 // ----------------------------------------------------------------------------
0019 // KDE Includes
0020 
0021 #include <KIO/FavIconRequestJob>
0022 #include <KIO/Job>
0023 #include <KLineEdit>
0024 #include <KLocalizedString>
0025 #include <KMessageBox>
0026 #include <kguiutils.h>
0027 
0028 // ----------------------------------------------------------------------------
0029 // Project Includes
0030 
0031 #include "ui_knewinstitutiondlg.h"
0032 
0033 #include "mymoneyinstitution.h"
0034 #include "kmymoneyutils.h"
0035 #include "icons.h"
0036 
0037 #include <errno.h>
0038 
0039 class KNewInstitutionDlgPrivate
0040 {
0041     Q_DISABLE_COPY(KNewInstitutionDlgPrivate)
0042 
0043 public:
0044     KNewInstitutionDlgPrivate() :
0045         ui(new Ui::KNewInstitutionDlg)
0046     {
0047         m_iconLoadTimer.setSingleShot(true);
0048     }
0049 
0050     ~KNewInstitutionDlgPrivate()
0051     {
0052         delete ui;
0053     }
0054 
0055     Ui::KNewInstitutionDlg*           ui;
0056     MyMoneyInstitution                m_institution;
0057     QTimer                            m_iconLoadTimer;
0058     QPointer<KIO::FavIconRequestJob>  m_favIconJob;
0059     QIcon                             m_favIcon;
0060     QString                           m_iconName;
0061     QUrl                              m_url;
0062 };
0063 
0064 KNewInstitutionDlg::KNewInstitutionDlg(MyMoneyInstitution& institution, QWidget *parent) :
0065     QDialog(parent),
0066     d_ptr(new KNewInstitutionDlgPrivate)
0067 {
0068     Q_D(KNewInstitutionDlg);
0069     d->ui->setupUi(this);
0070     d->m_institution = institution;
0071     setModal(true);
0072 
0073     d->ui->nameEdit->setFocus();
0074     d->ui->nameEdit->setText(institution.name());
0075     d->ui->cityEdit->setText(institution.city());
0076     d->ui->streetEdit->setText(institution.street());
0077     d->ui->postcodeEdit->setText(institution.postcode());
0078     d->ui->telephoneEdit->setText(institution.telephone());
0079     d->ui->bankCodeEdit->setText(institution.bankcode());
0080     d->ui->bicEdit->setText(institution.value(QStringLiteral("bic")));
0081     d->ui->urlEdit->setText(institution.value(QStringLiteral("url")));
0082     d->ui->iconUrlEdit->setText(institution.value(QStringLiteral("iconUrl")));
0083 
0084     if (!institution.value(QStringLiteral("icon")).isEmpty()) {
0085         d->m_favIcon = Icons::loadIconFromApplicationCache(institution.value(QStringLiteral("icon")));
0086     }
0087     if (!d->m_favIcon.isNull()) {
0088         d->ui->iconButton->setEnabled(true);
0089         d->ui->iconButton->setIcon(d->m_favIcon);
0090     }
0091 
0092     d->ui->messageWidget->hide();
0093 
0094     connect(d->ui->buttonBox, &QDialogButtonBox::accepted, this, &KNewInstitutionDlg::okClicked);
0095     connect(d->ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0096     connect(d->ui->nameEdit, &QLineEdit::textChanged, this, &KNewInstitutionDlg::institutionNameChanged);
0097     connect(d->ui->urlEdit, &QLineEdit::textChanged, this, [&]() {
0098         Q_D(KNewInstitutionDlg);
0099         slotUrlChanged(d->ui->urlEdit);
0100     });
0101     connect(d->ui->iconUrlEdit, &QLineEdit::textChanged, this, [&]() {
0102         Q_D(KNewInstitutionDlg);
0103         slotUrlChanged(d->ui->iconUrlEdit);
0104     });
0105     connect(&d->m_iconLoadTimer, &QTimer::timeout, this, &KNewInstitutionDlg::slotLoadIcon);
0106     connect(d->ui->iconButton, &QToolButton::pressed, this,
0107     [=] {
0108         QUrl url;
0109         url.setUrl(QString::fromLatin1("https://%1").arg(d->ui->urlEdit->text()));
0110         QDesktopServices::openUrl(url);
0111     });
0112     connect(d->ui->iconUrlEdit, &QLineEdit::textChanged, this, [&]() {
0113         Q_D(KNewInstitutionDlg);
0114         d->m_iconLoadTimer.start(200);
0115     });
0116 
0117     institutionNameChanged(d->ui->nameEdit->text());
0118     slotUrlChanged(d->ui->urlEdit);
0119 
0120     auto requiredFields = new KMandatoryFieldGroup(this);
0121     requiredFields->setOkButton(d->ui->buttonBox->button(QDialogButtonBox::Ok)); // button to be enabled when all fields present
0122     requiredFields->add(d->ui->nameEdit);
0123 }
0124 
0125 void KNewInstitutionDlg::institutionNameChanged(const QString &_text)
0126 {
0127     Q_D(KNewInstitutionDlg);
0128     d->ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!_text.isEmpty());
0129 }
0130 
0131 KNewInstitutionDlg::~KNewInstitutionDlg()
0132 {
0133     Q_D(KNewInstitutionDlg);
0134     delete d;
0135 }
0136 
0137 void KNewInstitutionDlg::okClicked()
0138 {
0139     Q_D(KNewInstitutionDlg);
0140     if (d->ui->nameEdit->text().isEmpty()) {
0141         KMessageBox::information(this, i18n("The institution name field is empty.  Please enter the name."), i18n("Adding New Institution"));
0142         d->ui->nameEdit->setFocus();
0143         return;
0144     }
0145 
0146     d->m_institution.setName(d->ui->nameEdit->text());
0147     d->m_institution.setTown(d->ui->cityEdit->text());
0148     d->m_institution.setStreet(d->ui->streetEdit->text());
0149     d->m_institution.setPostcode(d->ui->postcodeEdit->text());
0150     d->m_institution.setTelephone(d->ui->telephoneEdit->text());
0151     d->m_institution.setBankCode(d->ui->bankCodeEdit->text());
0152     d->m_institution.setValue(QStringLiteral("bic"), d->ui->bicEdit->text());
0153     d->m_institution.setValue(QStringLiteral("url"), d->ui->urlEdit->text());
0154     d->m_institution.setValue(QStringLiteral("iconUrl"), d->ui->iconUrlEdit->text());
0155     d->m_institution.deletePair(QStringLiteral("icon"));
0156 
0157     if (d->ui->iconButton->isEnabled()) {
0158         d->m_institution.setValue(QStringLiteral("icon"), d->m_iconName);
0159         Icons::storeIconInApplicationCache(d->m_iconName, d->m_favIcon);
0160     }
0161     accept();
0162 }
0163 
0164 const MyMoneyInstitution& KNewInstitutionDlg::institution()
0165 {
0166     Q_D(KNewInstitutionDlg);
0167     return d->m_institution;
0168 }
0169 
0170 void KNewInstitutionDlg::newInstitution(MyMoneyInstitution& institution)
0171 {
0172     institution.clearId();
0173     QPointer<KNewInstitutionDlg> dlg = new KNewInstitutionDlg(institution);
0174     if (dlg->exec() == QDialog::Accepted && dlg != 0) {
0175         institution = dlg->institution();
0176         KMyMoneyUtils::newInstitution(institution);
0177     }
0178     delete dlg;
0179 }
0180 
0181 void KNewInstitutionDlg::slotUrlChanged(QLineEdit* edit)
0182 {
0183     Q_D(KNewInstitutionDlg);
0184 
0185     // remove a possible leading protocol since we only provide https for now
0186     QRegularExpression protocol(QStringLiteral("^[a-zA-Z]+://(?<url>.*)"), QRegularExpression::CaseInsensitiveOption);
0187     QRegularExpressionMatch matcher = protocol.match(edit->text());
0188     if (matcher.hasMatch()) {
0189         edit->setText(matcher.captured(QStringLiteral("url")));
0190         d->ui->messageWidget->setText(i18nc("@info:usagetip", "The protocol part has been removed by KMyMoney because it is fixed to https for security reasons."));
0191         d->ui->messageWidget->setMessageType(KMessageWidget::Information);
0192         d->ui->messageWidget->animatedShow();
0193     }
0194     d->m_iconLoadTimer.start(200);
0195 }
0196 
0197 void KNewInstitutionDlg::slotLoadIcon()
0198 {
0199     Q_D(KNewInstitutionDlg);
0200 
0201     // if currently a check is running, retry later
0202     if (d->m_favIconJob) {
0203         d->m_iconLoadTimer.start(200);
0204         return;
0205     }
0206 
0207     const auto path = (d->ui->iconUrlEdit->text().isEmpty()) ? d->ui->urlEdit->text() : d->ui->iconUrlEdit->text();
0208     QRegularExpression urlRe(QStringLiteral("^(.*\\.)?[^\\.]{2,}\\.[a-z]{2,}"), QRegularExpression::CaseInsensitiveOption);
0209     QRegularExpressionMatch matcher = urlRe.match(path);
0210     d->ui->iconButton->setEnabled(false);
0211 
0212     if (matcher.hasMatch()) {
0213         d->ui->iconButton->setEnabled(true);
0214         d->m_url = QUrl(QString::fromLatin1("https://%1").arg(path));
0215         d->m_favIconJob = new KIO::FavIconRequestJob(d->m_url, KIO::Reload);
0216         connect(d->m_favIconJob, &KIO::FavIconRequestJob::result, this, &KNewInstitutionDlg::slotIconLoaded);
0217         // we force to end the job after 1 second to avoid blocking this mechanism in case the thing fails
0218         QTimer::singleShot(1000, this, &KNewInstitutionDlg::killIconLoad);
0219     }
0220 }
0221 
0222 void KNewInstitutionDlg::killIconLoad()
0223 {
0224     Q_D(KNewInstitutionDlg);
0225     if (d->m_favIconJob) {
0226         d->m_favIconJob->kill();
0227         d->m_favIconJob->deleteLater();
0228     }
0229 }
0230 
0231 void KNewInstitutionDlg::slotIconLoaded(KJob* job)
0232 {
0233     Q_D(KNewInstitutionDlg);
0234 
0235     switch(job->error()) {
0236     case ECONNREFUSED:
0237         // There is an answer from the server, but no favicon. In case we
0238         // already have one, we keep it
0239         d->ui->iconButton->setEnabled(true);
0240         d->m_favIcon = Icons::get(Icons::Icon::Institution);
0241         d->m_iconName = QStringLiteral("enum:Bank");
0242         break;
0243     case 0:
0244         // There is an answer from the server, and the favicon is found
0245         d->ui->iconButton->setEnabled(true);
0246         d->m_favIcon = QIcon(dynamic_cast<KIO::FavIconRequestJob*>(job)->iconFile());
0247         d->m_iconName = QStringLiteral("favicon:%1").arg(d->m_url.host());
0248         break;
0249     default:
0250         // There is problem with the URL from
0251         qDebug() << "KIO::FavIconRequestJob error" << job->error();
0252     // intentional fall through
0253 
0254     case EALREADY:    // invalid URL, no server response
0255         d->ui->iconButton->setEnabled(false);
0256         d->m_favIcon = QIcon();
0257         d->m_iconName.clear();
0258         break;
0259     }
0260     d->ui->iconButton->setIcon(d->m_favIcon);
0261 }