File indexing completed on 2024-04-28 05:08:23

0001 /***************************************************************************
0002     Copyright (C) 2005-2009 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #include <config.h>
0026 
0027 #include "loandialog.h"
0028 #include "borrowerdialog.h"
0029 #include "gui/datewidget.h"
0030 #include "collection.h"
0031 #include "commands/addloans.h"
0032 #include "commands/modifyloans.h"
0033 #include "utils/string_utils.h"
0034 #include "tellico_debug.h"
0035 
0036 #include <KLocalizedString>
0037 #include <KLineEdit>
0038 #include <KTextEdit>
0039 #include <KJob>
0040 #include <KSharedConfig>
0041 #include <KConfigGroup>
0042 #include <KWindowConfig>
0043 
0044 #ifdef HAVE_KABC
0045 #include <kcontacts/addressee.h>
0046 #include <Akonadi/Contact/ContactSearchJob>
0047 #endif
0048 
0049 #include <QLabel>
0050 #include <QCheckBox>
0051 #include <QGridLayout>
0052 #include <QPushButton>
0053 #include <QDialogButtonBox>
0054 #include <QVBoxLayout>
0055 #include <QTimer>
0056 
0057 namespace {
0058   static const char* dialogOptionsString = "Loan Dialog Options";
0059 }
0060 
0061 using Tellico::LoanDialog;
0062 
0063 LoanDialog::LoanDialog(const Tellico::Data::EntryList& entries_, QWidget* parent_)
0064     : QDialog(parent_),
0065       m_mode(Add), m_borrower(nullptr), m_entries(entries_), m_loan(nullptr) {
0066   setModal(true);
0067   setWindowTitle(i18n("Loan Dialog"));
0068 
0069   init();
0070 }
0071 
0072 LoanDialog::LoanDialog(Tellico::Data::LoanPtr loan_, QWidget* parent_)
0073     : QDialog(parent_),
0074       m_mode(Modify), m_borrower(loan_->borrower()), m_loan(loan_) {
0075   m_entries.append(m_loan->entry());
0076 
0077   setModal(true);
0078   setWindowTitle(i18n("Modify Loan"));
0079 
0080   init();
0081 
0082   m_borrowerEdit->setText(m_loan->borrower()->name());
0083   m_loanDate->setDate(m_loan->loanDate());
0084   if(m_loan->dueDate().isValid()) {
0085     m_dueDate->setDate(m_loan->dueDate());
0086 #ifdef HAVE_KCAL
0087     m_addEvent->setEnabled(true);
0088     if(m_loan->inCalendar()) {
0089       m_addEvent->setChecked(true);
0090     }
0091 #endif
0092   }
0093   m_note->setPlainText(m_loan->note());
0094 }
0095 
0096 void LoanDialog::init() {
0097   QVBoxLayout* mainLayout = new QVBoxLayout(this);
0098   setLayout(mainLayout);
0099 
0100   QWidget* mainWidget = new QWidget(this);
0101   mainLayout->addWidget(mainWidget);
0102 
0103   QGridLayout* topLayout = new QGridLayout(mainWidget);
0104   // middle column gets to be the widest
0105   topLayout->setColumnStretch(1, 1);
0106 
0107   int row = -1;
0108 
0109   QLabel* pixLabel = new QLabel(mainWidget);
0110   mainLayout->addWidget(pixLabel);
0111   pixLabel->setPixmap(QIcon::fromTheme(QStringLiteral("tellico"),
0112                                        QIcon(QLatin1String(":/icons/tellico")))
0113                                       .pixmap(QSize(64, 64)));
0114   pixLabel->setAlignment(Qt::Alignment(Qt::AlignLeft) | Qt::AlignTop);
0115   topLayout->addWidget(pixLabel, ++row, 0);
0116 
0117   QString entryString = QStringLiteral("<qt><p>");
0118   if(m_mode == Add) {
0119     entryString += i18n("The following items are being checked out:");
0120     entryString += QLatin1String("</p><ol>");
0121     foreach(Data::EntryPtr entry, m_entries) {
0122       entryString += QLatin1String("<li>") + entry->title() + QLatin1String("</li>");
0123     }
0124   } else {
0125     entryString += i18n("The following item is on-loan:");
0126     entryString += QLatin1String("</p><ol>");
0127     entryString += QLatin1String("<li>") + m_loan->entry()->title() + QLatin1String("</li>");
0128   }
0129   entryString += QLatin1String("</ol></qt>");
0130   KTextEdit* entryLabel = new KTextEdit(mainWidget);
0131   mainLayout->addWidget(entryLabel);
0132   entryLabel->setHtml(entryString);
0133   entryLabel->setReadOnly(true);
0134   topLayout->addWidget(entryLabel, row, 1, 1, 2);
0135 
0136   QLabel* l = new QLabel(i18n("&Lend to:"), mainWidget);
0137   mainLayout->addWidget(l);
0138   topLayout->addWidget(l, ++row, 0);
0139   m_borrowerEdit = new KLineEdit(mainWidget); //krazy:exclude=qclasses
0140   mainLayout->addWidget(m_borrowerEdit);
0141   topLayout->addWidget(m_borrowerEdit, row, 1);
0142   l->setBuddy(m_borrowerEdit);
0143   m_borrowerEdit->completionObject()->setIgnoreCase(true);
0144   connect(m_borrowerEdit, &QLineEdit::textChanged,
0145           this, &LoanDialog::slotBorrowerNameChanged);
0146   QPushButton* pb = new QPushButton(QIcon::fromTheme(QStringLiteral("kaddressbook")), QString(), mainWidget);
0147   mainLayout->addWidget(pb);
0148   topLayout->addWidget(pb, row, 2);
0149   connect(pb, &QAbstractButton::clicked, this, &LoanDialog::slotGetBorrower);
0150   QString whats = i18n("Enter the name of the person borrowing the items from you. "
0151                        "Clicking the button allows you to select from your address book.");
0152   l->setWhatsThis(whats);
0153   // only enable for new loans
0154   if(m_mode == Modify) {
0155     m_borrowerEdit->setEnabled(false);
0156     pb->setEnabled(false);
0157   }
0158 
0159   l = new QLabel(i18n("&Loan date:"), mainWidget);
0160   mainLayout->addWidget(l);
0161   topLayout->addWidget(l, ++row, 0);
0162   m_loanDate = new GUI::DateWidget(mainWidget);
0163   m_loanDate->setDate(QDate::currentDate());
0164   l->setBuddy(m_loanDate);
0165   topLayout->addWidget(m_loanDate, row, 1, 1, 2);
0166   whats = i18n("The check-out date is the date that you lent the items. By default, "
0167                "today's date is used.");
0168   l->setWhatsThis(whats);
0169   m_loanDate->setWhatsThis(whats);
0170   // only enable for new loans
0171   if(m_mode == Modify) {
0172     m_loanDate->setEnabled(false);
0173   }
0174 
0175   l = new QLabel(i18n("D&ue date:"), mainWidget);
0176   mainLayout->addWidget(l);
0177   topLayout->addWidget(l, ++row, 0);
0178   m_dueDate = new GUI::DateWidget(mainWidget);
0179   l->setBuddy(m_dueDate);
0180   topLayout->addWidget(m_dueDate, row, 1, 1, 2);
0181   // valid due dates will enable the calendar adding checkbox
0182   connect(m_dueDate, &GUI::DateWidget::signalModified, this, &LoanDialog::slotDueDateChanged);
0183   whats = i18n("The due date is when the items are due to be returned. The due date "
0184                "is not required, unless you want to add the loan to your active calendar.");
0185   l->setWhatsThis(whats);
0186   m_dueDate->setWhatsThis(whats);
0187 
0188   l = new QLabel(i18n("&Note:"), mainWidget);
0189   mainLayout->addWidget(l);
0190   topLayout->addWidget(l, ++row, 0);
0191   m_note = new KTextEdit(mainWidget);
0192   mainLayout->addWidget(m_note);
0193   l->setBuddy(m_note);
0194   topLayout->addWidget(m_note, row, 1, 1, 2);
0195   topLayout->setRowStretch(row, 1);
0196   whats = i18n("You can add notes about the loan.");
0197   l->setWhatsThis(whats);
0198   m_note->setWhatsThis(whats);
0199 
0200   m_addEvent = new QCheckBox(i18n("&Add a reminder to the active calendar"), mainWidget);
0201   mainLayout->addWidget(m_addEvent);
0202   topLayout->addWidget(m_addEvent, ++row, 0, 1, 3);
0203   m_addEvent->setEnabled(false); // gets enabled when valid due date is entered
0204   m_addEvent->setWhatsThis(i18n("<qt>Checking this box will add a <em>To-do</em> item "
0205                                    "to your active calendar, which can be viewed using KOrganizer. "
0206                                    "The box is only active if you set a due date.</qt>"));
0207 
0208 #ifdef HAVE_KABC
0209   // Search for all existing contacts
0210   Akonadi::ContactSearchJob* job = new Akonadi::ContactSearchJob();
0211   connect(job, SIGNAL(result(KJob*)), this, SLOT(akonadiSearchResult(KJob*)));
0212 #endif
0213   populateBorrowerList();
0214 
0215   m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
0216   QPushButton* okButton = m_buttonBox->button(QDialogButtonBox::Ok);
0217   okButton->setDefault(true);
0218   okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0219   okButton->setEnabled(false); // disable until a name is entered
0220   connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
0221   connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0222 
0223   mainLayout->addWidget(m_buttonBox);
0224 
0225   QTimer::singleShot(0, this, &LoanDialog::slotUpdateSize);
0226 }
0227 
0228 LoanDialog::~LoanDialog() {
0229   KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Loan Dialog Options"));
0230   KWindowConfig::saveWindowSize(windowHandle(), config);
0231 }
0232 
0233 void LoanDialog::slotBorrowerNameChanged(const QString& str_) {
0234   m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!str_.isEmpty());
0235 }
0236 
0237 void LoanDialog::slotDueDateChanged() {
0238 #ifdef HAVE_KCAL
0239   m_addEvent->setEnabled(m_dueDate->date().isValid());
0240 #endif
0241 }
0242 
0243 void LoanDialog::slotGetBorrower() {
0244   Data::BorrowerPtr borrower = BorrowerDialog::getBorrower(this);
0245   if(borrower) {
0246     m_borrowerEdit->setText(borrower->name());
0247     m_uid = borrower->uid();
0248   }
0249 }
0250 
0251 void LoanDialog::akonadiSearchResult(KJob* job_) {
0252   if(job_->error() != 0) {
0253     myDebug() << job_->errorString();
0254     return;
0255   }
0256 
0257 #ifdef HAVE_KABC
0258   Akonadi::ContactSearchJob* searchJob = qobject_cast<Akonadi::ContactSearchJob*>(job_);
0259   Q_ASSERT(searchJob);
0260 
0261   populateBorrowerList();
0262 
0263   foreach(const KContacts::Addressee& addressee, searchJob->contacts()) {
0264     // skip people with no name
0265     const QString name = addressee.realName().trimmed();
0266     if(name.isEmpty()) {
0267       continue;
0268     }
0269     m_borrowerEdit->completionObject()->addItem(name);
0270   }
0271 #endif
0272 }
0273 
0274 void LoanDialog::populateBorrowerList() {
0275   m_borrowerEdit->completionObject()->clear();
0276 
0277   // add current borrowers
0278   Data::BorrowerList borrowers = m_entries.at(0)->collection()->borrowers();
0279   foreach(Data::BorrowerPtr borrower, borrowers) {
0280     m_borrowerEdit->completionObject()->addItem(borrower->name());
0281   }
0282 }
0283 
0284 QUndoCommand* LoanDialog::createCommand() {
0285   // first, check to see if the borrower is empty
0286   QString name = m_borrowerEdit->text();
0287   if(name.isEmpty()) {
0288     return nullptr;
0289   }
0290 
0291   // ok, first handle creating new loans
0292   if(m_mode == Add) {
0293     return addLoansCommand();
0294   } else {
0295     return modifyLoansCommand();
0296   }
0297 }
0298 
0299 QUndoCommand* LoanDialog::addLoansCommand() {
0300   if(m_entries.isEmpty()) {
0301     return nullptr;
0302   }
0303 
0304   const QString name = m_borrowerEdit->text();
0305 
0306   // see if there's a borrower with this name already
0307   m_borrower = nullptr;
0308   Data::BorrowerList borrowers = m_entries.at(0)->collection()->borrowers();
0309   foreach(Data::BorrowerPtr borrower, borrowers) {
0310     if(borrower->name() == name) {
0311       m_borrower = borrower;
0312       break;
0313     }
0314   }
0315 
0316   if(!m_borrower) {
0317     if(m_uid.isEmpty()) {
0318       m_uid = Tellico::uid();
0319     }
0320     m_borrower = new Data::Borrower(name, m_uid);
0321   }
0322 
0323   Data::LoanList loans;
0324   foreach(Data::EntryPtr entry, m_entries) {
0325     loans.append(Data::LoanPtr(new Data::Loan(entry, m_loanDate->date(), m_dueDate->date(), m_note->toPlainText())));
0326   }
0327 
0328   return new Command::AddLoans(m_borrower, loans, m_addEvent->isChecked());
0329 }
0330 
0331 QUndoCommand* LoanDialog::modifyLoansCommand() {
0332   if(!m_loan) {
0333     return nullptr;
0334   }
0335 
0336   Data::LoanPtr newLoan(new Data::Loan(*m_loan));
0337   newLoan->setDueDate(m_dueDate->date());
0338   newLoan->setNote(m_note->toPlainText());
0339   return new Command::ModifyLoans(m_loan, newLoan, m_addEvent->isChecked());
0340 }
0341 
0342 void LoanDialog::slotUpdateSize() {
0343   KConfigGroup config(KSharedConfig::openConfig(), QLatin1String(dialogOptionsString));
0344   KWindowConfig::restoreWindowSize(windowHandle(), config);
0345 }