File indexing completed on 2024-10-27 04:20:57
0001 /* 0002 SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "locationhistorymodel.h" 0008 #include "logging.h" 0009 0010 #include <QDirIterator> 0011 #include <QJsonDocument> 0012 #include <QJsonObject> 0013 #include <QStandardPaths> 0014 0015 using namespace KPublicTransport; 0016 0017 static QString basePath() 0018 { 0019 #ifdef Q_OS_ANDROID 0020 constexpr auto dataLoc = QStandardPaths::AppDataLocation; 0021 #else 0022 constexpr auto dataLoc = QStandardPaths::GenericDataLocation; 0023 #endif 0024 return QStandardPaths::writableLocation(dataLoc) + QLatin1String("/org.kde.kpublictransport/location-history/"); 0025 } 0026 0027 LocationHistoryModel::LocationHistoryModel(QObject *parent) 0028 : QAbstractListModel(parent) 0029 { 0030 rescan(); 0031 } 0032 0033 LocationHistoryModel::~LocationHistoryModel() = default; 0034 0035 int LocationHistoryModel::rowCount(const QModelIndex &parent) const 0036 { 0037 if (parent.isValid()) { 0038 return 0; 0039 } 0040 return m_locations.size(); 0041 } 0042 0043 QVariant LocationHistoryModel::data(const QModelIndex &index, int role) const 0044 { 0045 if (!checkIndex(index)) { 0046 return {}; 0047 } 0048 0049 switch (role) { 0050 case LocationRole: return m_locations[index.row()].loc; 0051 case LocationNameRole: return m_locations[index.row()].loc.name(); 0052 case LastUsedRole: return m_locations[index.row()].lastUse; 0053 case UseCountRole: return m_locations[index.row()].useCount; 0054 } 0055 0056 return {}; 0057 } 0058 0059 QHash<int, QByteArray> LocationHistoryModel::roleNames() const 0060 { 0061 auto r = QAbstractListModel::roleNames(); 0062 r.insert(LocationRole, "location"); 0063 r.insert(LocationNameRole, "locationName"); 0064 r.insert(LastUsedRole, "lastUsed"); 0065 r.insert(UseCountRole, "useCount"); 0066 return r; 0067 } 0068 0069 bool LocationHistoryModel::removeRow(int row, const QModelIndex& parent) 0070 { 0071 return QAbstractListModel::removeRow(row, parent); 0072 } 0073 0074 bool LocationHistoryModel::removeRows(int row, int count, const QModelIndex &parent) 0075 { 0076 if (parent.isValid()) { 0077 return false; 0078 } 0079 0080 const auto path = basePath(); 0081 beginRemoveRows({}, row, row + count - 1); 0082 for (int i = row; i < row + count; ++i) { 0083 QFile::remove(path + m_locations[i].id); 0084 } 0085 m_locations.erase(m_locations.begin() + row, m_locations.begin() + row + count); 0086 endRemoveRows(); 0087 return true; 0088 } 0089 0090 void LocationHistoryModel::addLocation(const Location &loc) 0091 { 0092 for (auto it = m_locations.begin(); it != m_locations.end(); ++it) { 0093 if (Location::isSame((*it).loc, loc)) { 0094 (*it).loc = Location::merge((*it).loc, loc); 0095 (*it).lastUse = QDateTime::currentDateTime(); 0096 (*it).useCount++; 0097 store(*it); 0098 const auto idx = index(std::distance(m_locations.begin(), it)); 0099 Q_EMIT dataChanged(idx, idx); 0100 return; 0101 } 0102 } 0103 0104 Data data; 0105 data.id = QUuid::createUuid().toString(QUuid::WithoutBraces); 0106 data.loc = loc; 0107 data.lastUse = QDateTime::currentDateTime(); 0108 data.useCount = 1; 0109 store(data); 0110 0111 beginInsertRows({}, m_locations.size(), m_locations.size()); 0112 m_locations.push_back(std::move(data)); 0113 endInsertRows(); 0114 } 0115 0116 void LocationHistoryModel::clear() 0117 { 0118 beginResetModel(); 0119 const auto path = basePath(); 0120 for (const auto &data : m_locations) { 0121 QFile::remove(path + data.id); 0122 } 0123 m_locations.clear(); 0124 endResetModel(); 0125 } 0126 0127 void LocationHistoryModel::rescan() 0128 { 0129 beginResetModel(); 0130 for(QDirIterator it(basePath(), QDir::Files); it.hasNext();) { 0131 QFile f(it.next()); 0132 if (!f.open(QFile::ReadOnly)) { 0133 qCWarning(Log) << "Unable to read history entry:" << f.fileName() << f.errorString(); 0134 continue; 0135 } 0136 0137 const auto doc = QJsonDocument::fromJson(f.readAll()); 0138 const auto obj = doc.object(); 0139 Data data; 0140 data.id = it.fileInfo().baseName(); 0141 data.loc = Location::fromJson(obj.value(QLatin1String("location")).toObject()); 0142 data.lastUse = QDateTime::fromString(obj.value(QLatin1String("lastUse")).toString(), Qt::ISODate); 0143 data.useCount = obj.value(QLatin1String("useCount")).toInt(); 0144 m_locations.push_back(std::move(data)); 0145 } 0146 endResetModel(); 0147 } 0148 0149 void LocationHistoryModel::store(const LocationHistoryModel::Data &data) const 0150 { 0151 const auto path = basePath(); 0152 QDir().mkpath(path); 0153 0154 QFile f(path + data.id); 0155 if (!f.open(QFile::WriteOnly)) { 0156 qCWarning(Log) << "Unable to write history entry:" << f.fileName() << f.errorString(); 0157 return; 0158 } 0159 0160 QJsonObject obj; 0161 obj.insert(QLatin1String("location"), Location::toJson(data.loc)); 0162 obj.insert(QLatin1String("lastUse"), data.lastUse.toString(Qt::ISODate)); 0163 obj.insert(QLatin1String("useCount"), data.useCount); 0164 f.write(QJsonDocument(obj).toJson(QJsonDocument::Compact)); 0165 }