File indexing completed on 2024-05-19 04:48:14

0001 /*
0002  * <one line to give the program's name and a brief idea of what it does.>
0003  * Copyright (C) 2019  camilo <chiguitar@unal.edu.co>
0004  *
0005  * This program is free software: you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation, either version 3 of the License, or
0008  * (at your option) any later version.
0009  *
0010  * This program is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  * GNU General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU General Public License
0016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017  */
0018 
0019 #include "mauimodel.h"
0020 #include "mauilist.h"
0021 #include <QDebug>
0022 #include <QDateTime>
0023 #include <QRegularExpression>
0024 
0025 MauiModel::MauiModel(QObject *parent)
0026     : QSortFilterProxyModel(parent)
0027     , m_model(new PrivateAbstractListModel(this))
0028 {
0029    
0030 }
0031 
0032 QVariantMap MauiModel::get(const int &index) const
0033 {
0034     QVariantMap res;
0035     if (index >= this->rowCount() || index < 0)
0036         return res;
0037 
0038     const auto roleNames = this->roleNames();
0039     for (const auto &role : roleNames)
0040         res.insert(role, this->index(index, 0).data(FMH::MODEL_NAME_KEY[role]).toString());
0041 
0042     return res;
0043 }
0044 
0045 QVariantList MauiModel::getAll() const
0046 {
0047     QVariantList res;
0048     for (auto i = 0; i < this->rowCount(); i++)
0049         res << this->get(i);
0050 
0051     return res;
0052 }
0053 
0054 void MauiModel::setFilter(const QString &filter)
0055 {
0056     if (this->m_filter == filter)
0057         return;
0058 
0059 
0060     this->m_filter = filter;
0061     this->setFilterRegularExpression(this->m_filter);
0062     Q_EMIT this->filterChanged(this->m_filter);
0063     qDebug() << "Setting model filter" << m_filter;
0064 
0065 }
0066 
0067 const QString MauiModel::getFilter() const
0068 {
0069     return this->m_filter;
0070 }
0071 
0072 void MauiModel::setFilters(const QStringList& filters)
0073 {
0074     if (this->m_filters == filters)
0075         return;
0076     
0077     this->m_filters = filters;
0078     QString rx;
0079     for( int i = 0; i < m_filters.count(); ++i )
0080     {
0081         QString filter = QRegularExpression::escape( m_filters.at(i) );
0082         if( i > 0 )
0083             rx += '|';
0084         rx += filter;
0085     }
0086     qDebug() << "FILTERS" << filters << m_filters << m_filter << rx << filterCaseSensitivity() << ( filterCaseSensitivity() == Qt::CaseSensitivity::CaseSensitive);
0087     QRegularExpression reg(rx, filterCaseSensitivity() == Qt::CaseSensitivity::CaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption);
0088 //    reg.setCaseSensitivity(filterCaseSensitivity());
0089     this->setFilterRegularExpression(reg);
0090     Q_EMIT this->filtersChanged(this->m_filters);
0091 }
0092 
0093 const QStringList MauiModel::getFilters() const
0094 {
0095     return m_filters;
0096 }
0097 
0098 void MauiModel::clearFilters()
0099 {   
0100     this->m_filter.clear();
0101     this->m_filters.clear();
0102     this->setFilterFixedString("");
0103     this->setFilterRegularExpression("");
0104     this->invalidateFilter();
0105     Q_EMIT this->filtersChanged(this->m_filters);
0106     Q_EMIT this->filterChanged(this->m_filter);
0107     
0108 }
0109 
0110 void MauiModel::PrivateAbstractListModel::reset()
0111 { 
0112     this->beginResetModel();
0113     this->endResetModel();    
0114 }
0115 
0116 QString MauiModel::getFilterRoleName() const
0117 {
0118     return m_filter;
0119 }
0120 
0121 void MauiModel::setSortOrder(const Qt::SortOrder &sortOrder)
0122 {
0123     if (this->m_sortOrder == sortOrder)
0124         return;
0125 
0126     this->m_sortOrder = sortOrder;
0127     Q_EMIT this->sortOrderChanged(this->m_sortOrder);
0128     this->sort(0, this->m_sortOrder);
0129 }
0130 
0131 Qt::SortOrder MauiModel::getSortOrder() const
0132 {
0133     return this->m_sortOrder;
0134 }
0135 
0136 void MauiModel::setSort(const QString &sort)
0137 {
0138     if (this->m_sort == sort)
0139         return;
0140 
0141     this->m_sort = sort;
0142     Q_EMIT this->sortChanged(this->m_sort);
0143     this->setSortRole(FMH::MODEL_NAME_KEY[sort]);
0144     this->sort(0, this->m_sortOrder);
0145 }
0146 
0147 QString MauiModel::getSort() const
0148 {
0149     return this->m_sort;
0150 }
0151 
0152 int MauiModel::count() const
0153 {
0154     return this->rowCount();
0155 }
0156 
0157 int MauiModel::mappedFromSource(const int &index) const
0158 {
0159     return this->mapFromSource(this->m_model->index(index, 0)).row();
0160 }
0161 
0162 int MauiModel::mappedToSource(const int &index) const
0163 {
0164     return this->mapToSource(this->index(index, 0)).row();
0165 }
0166 
0167 void MauiModel::setFilterRoleName(QString filter)
0168 {
0169     if (m_filterRoleName == filter)
0170         return;
0171 
0172     m_filterRoleName = filter;
0173     Q_EMIT filterRoleNameChanged(m_filterRoleName);
0174     this->setFilterRole(FMH::MODEL_NAME_KEY[m_filterRoleName]);
0175 }
0176 
0177 bool MauiModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
0178 {
0179     if (this->filterRole() != Qt::DisplayRole) {
0180         QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
0181         const auto data = this->sourceModel()->data(index, this->filterRole()).toString();
0182         return data.contains(this->filterRegularExpression());
0183     }
0184 
0185     const auto roleNames = this->sourceModel()->roleNames();
0186     for (const auto &role : roleNames) {
0187         QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
0188         const auto data = this->sourceModel()->data(index, FMH::MODEL_NAME_KEY[role]).toString();
0189         if (data.contains(this->filterRegularExpression()))
0190             return true;
0191         else
0192             continue;
0193     }
0194 
0195     return false;
0196 }
0197 
0198 MauiList *MauiModel::getList() const
0199 {
0200     return this->m_list;
0201 }
0202 
0203 void MauiModel::PrivateAbstractListModel::setUpList()
0204 {
0205     beginResetModel();
0206 
0207     if (m_model->getList())
0208         m_model->getList()->disconnect(this);
0209 
0210     if (m_model->getList()) {
0211         connect(
0212             m_model->getList(),
0213             &MauiList::preItemAppendedAt,
0214             this,
0215             [this](int index) {
0216                 beginInsertRows(QModelIndex(), index, index);
0217             },
0218             Qt::DirectConnection);
0219 
0220         connect(
0221             m_model->getList(),
0222             &MauiList::preItemAppended,
0223             this,
0224             [this]() {
0225                 const int index = m_model->getList()->getCount();
0226                 beginInsertRows(QModelIndex(), index, index);
0227             },
0228             Qt::DirectConnection);
0229 
0230         connect(
0231             m_model->getList(),
0232             &MauiList::preItemsAppended,
0233             this,
0234             [this](uint count) {
0235                 const int index = m_model->getList()->getCount();
0236                 beginInsertRows(QModelIndex(), index, index + count - 1);
0237             },
0238             Qt::DirectConnection);
0239 
0240         connect(
0241             m_model->getList(),
0242             &MauiList::postItemAppended,
0243             this,
0244             [this]() {
0245                 endInsertRows();
0246             },
0247             Qt::DirectConnection);
0248 
0249         connect(
0250             m_model->getList(),
0251             &MauiList::preItemRemoved,
0252             this,
0253             [this](int index) {
0254                 beginRemoveRows(QModelIndex(), index, index);
0255             },
0256             Qt::DirectConnection);
0257 
0258         connect(
0259             m_model->getList(),
0260             &MauiList::postItemRemoved,
0261             this,
0262             [this]() {
0263                 endRemoveRows();
0264             },
0265             Qt::DirectConnection);
0266 
0267         connect(
0268             m_model->getList(),
0269             &MauiList::updateModel,
0270             this,
0271             [this](int index, QVector<int> roles) {
0272                 Q_EMIT this->dataChanged(this->m_model->index(index, 0), this->m_model->index(index, 0), roles);
0273             },
0274             Qt::DirectConnection);
0275 
0276         connect(
0277             m_model->getList(),
0278             &MauiList::preListChanged,
0279             this,
0280             [this]() {
0281                 beginResetModel();
0282             },
0283             Qt::DirectConnection);
0284 
0285         connect(
0286             m_model->getList(),
0287             &MauiList::postListChanged,
0288             this,
0289             [this]() {
0290                 endResetModel();
0291             },
0292             Qt::DirectConnection);
0293         
0294         connect(
0295             m_model->getList(),
0296                 &MauiList::itemMoved,
0297                 m_model, &MauiModel::move,
0298                 Qt::DirectConnection);
0299     }
0300 
0301     endResetModel();
0302 }
0303 
0304 void MauiModel::setList(MauiList *value)
0305 {
0306     if(value && value != this->m_list)
0307     {
0308         this->m_list = value;
0309         this->m_list->modelHooked();
0310         
0311         this->m_model->setUpList();
0312         Q_EMIT this->listChanged();
0313         
0314         this->setSourceModel(this->m_model);
0315         this->setDynamicSortFilter(true);
0316     }
0317 }
0318 
0319 MauiModel::PrivateAbstractListModel::PrivateAbstractListModel(MauiModel *model)
0320     : QAbstractListModel(model)
0321     , m_model(model)
0322 {
0323     connect(
0324         this,
0325         &QAbstractListModel::rowsInserted,
0326         this,
0327         [this](QModelIndex, int, int) {
0328             if (m_model->getList()) {
0329                 Q_EMIT this->m_model->countChanged();
0330             }
0331         },
0332         Qt::DirectConnection);
0333 
0334     connect(
0335         this,
0336         &QAbstractListModel::rowsRemoved,
0337         this,
0338         [this](QModelIndex, int, int) {
0339             if (m_model->getList()) {
0340                 Q_EMIT this->m_model->countChanged();
0341             }
0342         },
0343         Qt::DirectConnection);
0344 }
0345 
0346 int MauiModel::PrivateAbstractListModel::rowCount(const QModelIndex &parent) const
0347 {
0348     if (parent.isValid() || !m_model->getList())
0349     {        
0350         return 0;
0351     }    
0352         
0353     return m_model->getList()->getCount();
0354 }
0355     
0356 
0357 QVariant MauiModel::PrivateAbstractListModel::data(const QModelIndex &index, int role) const
0358 {
0359     if (!index.isValid() || !m_model->getList())
0360         return QVariant();
0361 
0362     auto value = m_model->getList()->getItem(index.row()).value(static_cast<FMH::MODEL_KEY>(role));
0363 
0364     if (role == FMH::MODEL_KEY::ADDDATE || role == FMH::MODEL_KEY::DATE || role == FMH::MODEL_KEY::MODIFIED || role == FMH::MODEL_KEY::RELEASEDATE) {
0365         const auto date = QDateTime::fromString(value, Qt::TextDate);
0366         if (date.isValid())
0367             return date;
0368     }
0369 
0370     return value;
0371 }
0372 
0373 bool MauiModel::PrivateAbstractListModel::setData(const QModelIndex &index, const QVariant &value, int role)
0374 {
0375     Q_UNUSED(index);
0376     Q_UNUSED(value);
0377     Q_UNUSED(role);
0378 
0379     return false;
0380 }
0381 
0382 Qt::ItemFlags MauiModel::PrivateAbstractListModel::flags(const QModelIndex &index) const
0383 {
0384     if (!index.isValid())
0385         return Qt::NoItemFlags;
0386 
0387     return Qt::ItemIsEditable; // FIXME: Implement me!
0388 }
0389 
0390 QHash<int, QByteArray> MauiModel::PrivateAbstractListModel::roleNames() const
0391 {
0392     QHash<int, QByteArray> names;
0393     const auto keys = FMH::MODEL_NAME.keys();
0394 
0395     for (const auto &key : keys)
0396     {
0397         names[key] = QString(FMH::MODEL_NAME[key]).toUtf8();
0398     }
0399 
0400     return names;
0401 }
0402 
0403 bool MauiModel::move(const int &index, const int &to)
0404 {
0405     if(index == to)
0406         return false;
0407     
0408     if(index>=0 && index< count())
0409     {
0410         if(to >= count() || to < 0)
0411             return false;
0412         
0413         beginMoveRows(QModelIndex(), index, index, QModelIndex(), index < to ? to+1 : to);
0414         endMoveRows();
0415     }
0416     
0417     return true;
0418 }
0419 
0420 /*!
0421  * Must be reimplemented, because moving rows should be possible
0422  * \brief ListModel::moveRows
0423  * \param sourceParent
0424  * \param sourceRow
0425  * \param count
0426  * \param destinationParent
0427  * \param destinationChild
0428  * \return
0429  */
0430 bool MauiModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) {
0431     if (sourceRow < 0
0432         //|| sourceRow + count - 1 >= rowCount(sourceParent)
0433         || destinationChild <= 0
0434         //|| destinationChild > rowCount(destinationParent)
0435         || sourceRow == destinationChild - 1
0436         || count <= 0) {
0437         return false;
0438         }
0439         
0440         return true;
0441 }
0442 
0443 bool MauiModel::moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild) {
0444     
0445     return true;
0446 }
0447