File indexing completed on 2025-02-02 05:02:39

0001 /*
0002     SPDX-FileCopyrightText: 2018 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "tripgroupproxymodel.h"
0008 #include "timelinemodel.h"
0009 #include "tripgroup.h"
0010 #include "tripgroupmanager.h"
0011 
0012 #include <QDebug>
0013 #include <QSettings>
0014 
0015 TripGroupProxyModel::TripGroupProxyModel(QObject *parent)
0016     : QSortFilterProxyModel(parent)
0017 {
0018     QSettings settings;
0019     settings.beginGroup(QLatin1StringView("TripGroupProxyState"));
0020     for (const auto &key : settings.childKeys()) {
0021         m_collapsed[key] = settings.value(key).toBool();
0022     }
0023 }
0024 
0025 TripGroupProxyModel::~TripGroupProxyModel() = default;
0026 
0027 void TripGroupProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
0028 {
0029     m_sourceModel = qobject_cast<TimelineModel*>(sourceModel);
0030     Q_ASSERT(m_sourceModel);
0031     connect(m_sourceModel, &TimelineModel::todayRowChanged, this, &TripGroupProxyModel::todayRowChanged);
0032     connect(m_sourceModel, &TimelineModel::todayRowChanged, this, &TripGroupProxyModel::invalidateFilter);
0033     QSortFilterProxyModel::setSourceModel(m_sourceModel);
0034 }
0035 
0036 QVariant TripGroupProxyModel::data(const QModelIndex &index, int role) const
0037 {
0038     if (role == TimelineModel::ElementRangeRole) {
0039         const auto srcIdx = mapToSource(index);
0040         const auto elementType = srcIdx.data(TimelineModel::ElementTypeRole).toInt();
0041         const auto rangeType = srcIdx.data(TimelineModel::ElementRangeRole).toInt();
0042         if (elementType == TimelineElement::TripGroup && rangeType == TimelineElement::RangeBegin) {
0043             const auto groupId = srcIdx.data(TimelineModel::TripGroupIdRole).toString();
0044             if (isCollapsed(groupId)) {
0045                 return TimelineElement::SelfContained;
0046             }
0047         }
0048     }
0049     return QSortFilterProxyModel::data(index, role);
0050 }
0051 
0052 bool TripGroupProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
0053 {
0054     // ### we can probably do this more efficiently!
0055     for (int i = source_row; i < m_sourceModel->rowCount(); ++i) {
0056         const auto srcIdx = m_sourceModel->index(i, 0);
0057         const auto elementType = srcIdx.data(TimelineModel::ElementTypeRole).toInt();
0058         const auto rangeType = srcIdx.data(TimelineModel::ElementRangeRole).toInt();
0059         if (elementType == TimelineElement::TripGroup && rangeType == TimelineElement::RangeBegin) {
0060             // either this is our group's start, or a group after us
0061             return true;
0062         }
0063         if (elementType != TimelineElement::TripGroup) {
0064             continue;
0065         }
0066         const auto groupId = srcIdx.data(TimelineModel::TripGroupIdRole).toString();
0067         return !isCollapsed(groupId);
0068     }
0069 
0070     return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
0071 }
0072 
0073 int TripGroupProxyModel::todayRow()
0074 {
0075     const auto srcIdx = m_sourceModel->index(m_sourceModel->todayRow(), 0);
0076     return mapFromSource(srcIdx).row();
0077 }
0078 
0079 void TripGroupProxyModel::collapse(const QString &groupId)
0080 {
0081     m_collapsed[groupId] = true;
0082     invalidateFilter();
0083 
0084     const auto startSrcIdx = m_sourceModel->match(m_sourceModel->index(0, 0), TimelineModel::TripGroupIdRole, groupId, 1, Qt::MatchExactly).at(0);
0085     Q_ASSERT(startSrcIdx.isValid());
0086     const auto startIdx = mapFromSource(startSrcIdx);
0087     Q_EMIT dataChanged(startIdx, startIdx); // collapse/expand state changed
0088 
0089     QSettings settings;
0090     settings.beginGroup(QLatin1StringView("TripGroupProxyState"));
0091     settings.setValue(groupId, true);
0092 }
0093 
0094 void TripGroupProxyModel::expand(const QString &groupId)
0095 {
0096     m_collapsed[groupId] = false;
0097     invalidateFilter();
0098 
0099     const auto startSrcIdx = m_sourceModel->match(m_sourceModel->index(0, 0), TimelineModel::TripGroupIdRole, groupId, 1, Qt::MatchExactly).at(0);
0100     Q_ASSERT(startSrcIdx.isValid());
0101     const auto startIdx = mapFromSource(startSrcIdx);
0102     Q_EMIT dataChanged(startIdx, startIdx); // collapse/expand state changed
0103 
0104     QSettings settings;
0105     settings.beginGroup(QLatin1StringView("TripGroupProxyState"));
0106     settings.setValue(groupId, false);
0107 }
0108 
0109 bool TripGroupProxyModel::isCollapsed(const QString &groupId) const
0110 {
0111     const auto g = m_sourceModel->tripGroupManager()->tripGroup(groupId);
0112     const auto now = m_sourceModel->now();
0113     if (g.beginDateTime() <= now && now <= g.endDateTime()) {
0114         return false; // the current trip must always be expanded
0115     }
0116 
0117     const auto it = m_collapsed.constFind(groupId);
0118     if (it != m_collapsed.constEnd()) {
0119         return it.value();
0120     }
0121 
0122     // by default collapse past trips
0123     return g.endDateTime() < now;
0124 }
0125 
0126 #include "moc_tripgroupproxymodel.cpp"