File indexing completed on 2024-05-12 05:09:51

0001 /***************************************************************************
0002     Copyright (C) 2008-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 "borrowermodel.h"
0026 #include "models.h"
0027 #include "../collectionfactory.h"
0028 #include "../entry.h"
0029 #include "../tellico_debug.h"
0030 
0031 #include <KLocalizedString>
0032 
0033 #include <QIcon>
0034 
0035 using Tellico::BorrowerModel;
0036 
0037 class BorrowerModel::Node {
0038 public:
0039   Node(Node* parent_) : m_parent(parent_) {}
0040   ~Node() { qDeleteAll(m_children); }
0041 
0042   Node* parent() const { return m_parent; }
0043   Node* child(int row) const { return m_children.at(row); }
0044   int row() const { return m_parent ? m_parent->m_children.indexOf(const_cast<Node*>(this)) : 0; }
0045   int childCount() const { return m_children.count(); }
0046 
0047   void addChild(Node* child) {  m_children.append(child); }
0048   void replaceChild(int i, Node* child) {  m_children.replace(i, child); }
0049   void removeChild(int i) {  delete m_children.takeAt(i); }
0050   void removeAll() { qDeleteAll(m_children); m_children.clear(); }
0051 
0052 private:
0053   Node* m_parent;
0054   QList<Node*> m_children;
0055 };
0056 
0057 BorrowerModel::BorrowerModel(QObject* parent) : QAbstractItemModel(parent), m_rootNode(new Node(nullptr)) {
0058 }
0059 
0060 BorrowerModel::~BorrowerModel() {
0061   delete m_rootNode;
0062   m_rootNode = nullptr;
0063 }
0064 
0065 int BorrowerModel::rowCount(const QModelIndex& index_) const {
0066   if(!index_.isValid()) {
0067     return m_borrowers.count();
0068   }
0069   QModelIndex parent = index_.parent();
0070   if(parent.isValid()) {
0071     return 0; // a parent index means it points to an entry, not a filter, so there are no children
0072   }
0073   Node* node = static_cast<Node*>(index_.internalPointer());
0074   Q_ASSERT(node);
0075   return node->childCount();
0076 }
0077 
0078 int BorrowerModel::columnCount(const QModelIndex&) const {
0079   return 1;
0080 }
0081 
0082 QVariant BorrowerModel::headerData(int section_, Qt::Orientation orientation_, int role_) const {
0083   if(section_ < 0 || section_ >= columnCount() || orientation_ != Qt::Horizontal) {
0084     return QVariant();
0085   }
0086   if(role_ == Qt::DisplayRole) {
0087     return m_header;
0088   }
0089   return QVariant();
0090 }
0091 
0092 bool BorrowerModel::setHeaderData(int section_, Qt::Orientation orientation_,
0093                                   const QVariant& value_, int role_) {
0094   if(section_ < 0 || section_ >= columnCount() || orientation_ != Qt::Horizontal || role_ != Qt::EditRole) {
0095     return false;
0096   }
0097   m_header = value_.toString();
0098   emit headerDataChanged(orientation_, section_, section_);
0099   return true;
0100 }
0101 
0102 QVariant BorrowerModel::data(const QModelIndex& index_, int role_) const {
0103   if(!index_.isValid()) {
0104     return QVariant();
0105   }
0106 
0107   QModelIndex parent = index_.parent();
0108 
0109   if(index_.row() >= rowCount(parent)) {
0110     return QVariant();
0111   }
0112 
0113   switch(role_) {
0114     case Qt::DisplayRole:
0115       if(parent.isValid()) {
0116         // it points to an entry
0117         return entry(index_)->title();
0118       }
0119       // it points to a borrower
0120       return borrower(index_)->name();
0121     case Qt::DecorationRole:
0122       return parent.isValid() ? QIcon(QLatin1String(":/icons/") + CollectionFactory::typeName(entry(index_)->collection()))
0123                               : QIcon::fromTheme(QLatin1String("kaddressbook"));
0124     case RowCountRole:
0125       return rowCount(index_);
0126     case EntryPtrRole:
0127       return QVariant::fromValue(entry(index_));
0128   }
0129 
0130   return QVariant();
0131 }
0132 
0133 QModelIndex BorrowerModel::index(int row_, int column_, const QModelIndex& parent_) const {
0134   if(!hasIndex(row_, column_, parent_)) {
0135     return QModelIndex();
0136   }
0137 
0138   Node* parentNode;
0139   if(parent_.isValid()) {
0140     parentNode = static_cast<Node*>(parent_.internalPointer());
0141   } else {
0142     parentNode = m_rootNode;
0143   }
0144 
0145   Node* child = parentNode->child(row_);
0146   if(!child) {
0147     return QModelIndex();
0148   }
0149   return createIndex(row_, column_, child);
0150 }
0151 
0152 QModelIndex BorrowerModel::parent(const QModelIndex& index_) const {
0153   if(!index_.isValid()) {
0154     return QModelIndex();
0155   }
0156 
0157   Node* node = static_cast<Node*>(index_.internalPointer());
0158   Q_ASSERT(node);
0159   Node* parentNode = node->parent();
0160   Q_ASSERT(parentNode);
0161 
0162   // if it's top-level, it has no parent
0163   if(parentNode == m_rootNode) {
0164     return QModelIndex();
0165   }
0166   return createIndex(parentNode->row(), 0, parentNode);
0167 }
0168 
0169 void BorrowerModel::clear() {
0170   beginResetModel();
0171   m_borrowers.clear();
0172   delete m_rootNode;
0173   m_rootNode = new Node(nullptr);
0174   endResetModel();
0175 }
0176 
0177 void BorrowerModel::addBorrowers(const Tellico::Data::BorrowerList& borrowers_) {
0178   beginInsertRows(QModelIndex(), rowCount(), rowCount()+borrowers_.count()-1);
0179   m_borrowers += borrowers_;
0180   foreach(Data::BorrowerPtr borrower, borrowers_) {
0181     Node* borrowerNode = new Node(m_rootNode);
0182     m_rootNode->addChild(borrowerNode);
0183     for(int i = 0; i < borrower->count(); ++i) {
0184       Node* childNode = new Node(borrowerNode);
0185       borrowerNode->addChild(childNode);
0186     }
0187   }
0188   endInsertRows();
0189 }
0190 
0191 QModelIndex BorrowerModel::addBorrower(Tellico::Data::BorrowerPtr borrower_) {
0192   Q_ASSERT(borrower_);
0193   addBorrowers(Data::BorrowerList() << borrower_);
0194   // rowCount() has increased now
0195   return index(rowCount()-1, 0);
0196 }
0197 
0198 QModelIndex BorrowerModel::modifyBorrower(Tellico::Data::BorrowerPtr borrower_) {
0199   Q_ASSERT(borrower_);
0200   Q_ASSERT(!borrower_->isEmpty());
0201   int idx = m_borrowers.indexOf(borrower_);
0202   if(idx < 0) {
0203     myWarning() << "no borrower named" << borrower_->name();
0204     return QModelIndex();
0205   }
0206 
0207   QModelIndex borrowerIndex = index(idx, 0);
0208   Node* borrowerNode = m_rootNode->child(idx);
0209 
0210   beginRemoveRows(borrowerIndex, 0, borrowerNode->childCount() - 1);
0211   borrowerNode->removeAll();
0212   endRemoveRows();
0213 
0214   beginInsertRows(borrowerIndex, 0, borrower_->count() - 1);
0215   for(int i = 0; i < borrower_->count(); ++i) {
0216     Node* childNode = new Node(borrowerNode);
0217     borrowerNode->addChild(childNode);
0218   }
0219   endInsertRows();
0220 
0221   emit dataChanged(borrowerIndex, borrowerIndex);
0222   return borrowerIndex;
0223 }
0224 
0225 void BorrowerModel::removeBorrower(Tellico::Data::BorrowerPtr borrower_) {
0226   Q_ASSERT(borrower_);
0227   int idx = m_borrowers.indexOf(borrower_);
0228   if(idx < 0) {
0229     myWarning() << "no borrower named" << borrower_->name();
0230     return;
0231   }
0232 
0233   beginRemoveRows(QModelIndex(), idx, idx);
0234   m_borrowers.removeAt(idx);
0235   m_rootNode->removeChild(idx);
0236   endRemoveRows();
0237 }
0238 
0239 Tellico::Data::BorrowerPtr BorrowerModel::borrower(const QModelIndex& index_) const {
0240   // if the parent isn't invalid, then it's not a top-level borrower
0241   if(!index_.isValid() || index_.parent().isValid() || index_.row() >= m_borrowers.count()) {
0242     return Data::BorrowerPtr();
0243   }
0244   return m_borrowers.at(index_.row());
0245 }
0246 
0247 Tellico::Data::EntryPtr BorrowerModel::entry(const QModelIndex& index_) const {
0248   // if there's not a parent, then it's a top-level item, no entry
0249   if(!index_.parent().isValid()) {
0250     return Data::EntryPtr();
0251   }
0252   Data::EntryPtr entry;
0253   Data::LoanPtr loan = this->loan(index_);
0254   if(loan) {
0255     entry = loan->entry();
0256   }
0257   return entry;
0258 }
0259 
0260 Tellico::Data::LoanPtr BorrowerModel::loan(const QModelIndex& index_) const {
0261   // if there's not a parent, then it's a top-level item, no entry
0262   if(!index_.parent().isValid()) {
0263     return Data::LoanPtr();
0264   }
0265   Data::LoanPtr loan;
0266   Data::BorrowerPtr borrower = this->borrower(index_.parent());
0267   // could have already removed the loan from the borrower
0268   if(borrower && index_.row() < borrower->loans().size()) {
0269     loan = borrower->loans().at(index_.row());
0270   }
0271   return loan;
0272 }