File indexing completed on 2024-05-19 16:51:56
0001 /* 0002 Copyright (C) 2015 by Elvis Angelaccio <elvis.angelaccio@kde.org> 0003 0004 This file is part of Kronometer. 0005 0006 Kronometer is free software: you can redistribute it and/or modify 0007 it under the terms of the GNU General Public License as published by 0008 the Free Software Foundation, either version 2 of the License, or 0009 (at your option) any later version. 0010 0011 Kronometer is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 GNU General Public License for more details. 0015 0016 You should have received a copy of the GNU General Public License 0017 along with Kronometer. If not, see <http://www.gnu.org/licenses/>. 0018 */ 0019 0020 #include "sessionmodel.h" 0021 0022 #include <KLocalizedString> 0023 0024 #include <QDebug> 0025 #include <QFile> 0026 #include <QJsonArray> 0027 #include <QJsonDocument> 0028 #include <QJsonObject> 0029 #include <QStandardPaths> 0030 0031 SessionModel::SessionModel(QObject *parent) : QAbstractTableModel(parent) 0032 { 0033 QFile saveFile {QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QLatin1String("/sessions.json")}; 0034 if (saveFile.exists()) { 0035 if (saveFile.open(QIODevice::ReadOnly)) { 0036 auto saveData = saveFile.readAll(); 0037 auto saveDoc = QJsonDocument::fromJson(saveData); 0038 read(saveDoc.object()); 0039 } else { 0040 qDebug().nospace() << "cannot open " << saveFile.fileName() << ": " << saveFile.errorString(); 0041 } 0042 } 0043 0044 connect(this, &QAbstractTableModel::dataChanged, this, &SessionModel::slotWriteData); 0045 connect(this, &QAbstractTableModel::rowsInserted, this, &SessionModel::slotWriteData); 0046 connect(this, &QAbstractTableModel::rowsRemoved, this, &SessionModel::slotWriteData); 0047 } 0048 0049 int SessionModel::columnCount(const QModelIndex& parent) const 0050 { 0051 Q_UNUSED(parent) 0052 0053 return m_roles.count(); 0054 } 0055 0056 int SessionModel::rowCount(const QModelIndex& parent) const 0057 { 0058 Q_UNUSED(parent) 0059 0060 return m_sessionList.size(); 0061 } 0062 0063 QVariant SessionModel::data(const QModelIndex& index, int role) const 0064 { 0065 if (not index.isValid()) { 0066 return QVariant::Invalid; 0067 } 0068 0069 if (index.row() >= rowCount() or index.row() < 0) { 0070 return QVariant::Invalid; 0071 } 0072 0073 if (role == Qt::DisplayRole) { 0074 return data(index, Qt::UserRole + index.column()); 0075 } 0076 0077 switch (static_cast<Roles>(role)) { 0078 case Roles::SessionIdRole: 0079 return QString::number(index.row() + 1); 0080 case Roles::NameRole: 0081 return m_sessionList.at(index.row()).name(); 0082 case Roles::DateRole: 0083 return m_sessionList.at(index.row()).date(); 0084 case Roles::NoteRole: 0085 return m_sessionList.at(index.row()).note(); 0086 case Roles::SessionRole: 0087 return QVariant::fromValue(m_sessionList.at(index.row())); 0088 } 0089 0090 if (role == Qt::EditRole && index.column() == columnForRole(Roles::NameRole)) { 0091 // prevent the disappear of the old value when double-clicking the item 0092 return m_sessionList.at(index.row()).name(); 0093 } 0094 0095 if (role == Qt::EditRole && index.column() == columnForRole(Roles::NoteRole)) { 0096 return m_sessionList.at(index.row()).note(); 0097 } 0098 0099 return QVariant::Invalid; 0100 } 0101 0102 0103 QVariant SessionModel::headerData(int section, Qt::Orientation orientation, int role) const 0104 { 0105 if (role != Qt::DisplayRole or orientation != Qt::Horizontal) 0106 return QVariant::Invalid; 0107 0108 switch (roleForColumn(section)) { 0109 case Roles::SessionIdRole: 0110 return i18nc("session number", "Session #"); 0111 case Roles::NameRole: 0112 return i18n("Name"); 0113 case Roles::DateRole: 0114 return i18n("Date"); 0115 case Roles::NoteRole: 0116 return i18n("Note"); 0117 case Roles::SessionRole: 0118 break; 0119 } 0120 0121 return QVariant::Invalid; 0122 } 0123 0124 bool SessionModel::setData(const QModelIndex& index, const QVariant& value, int role) 0125 { 0126 if (not index.isValid() or role != Qt::EditRole) 0127 return false; 0128 0129 if (index.column() == columnForRole(Roles::NameRole)) { 0130 if (value.toString().isEmpty()) 0131 return false; 0132 0133 m_sessionList[index.row()].setName(value.toString()); 0134 emit dataChanged(index, index); 0135 0136 return true; 0137 } 0138 0139 if (index.column() == columnForRole(Roles::NoteRole)) { 0140 m_sessionList[index.row()].setNote(value.toString()); 0141 emit dataChanged(index, index); 0142 0143 return true; 0144 } 0145 0146 return false; 0147 } 0148 0149 Qt::ItemFlags SessionModel::flags(const QModelIndex& index) const 0150 { 0151 if (not index.isValid()) 0152 return Qt::ItemIsEnabled; 0153 0154 if (isEditable(index)) 0155 return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; 0156 0157 return QAbstractTableModel::flags(index); 0158 } 0159 0160 bool SessionModel::removeRows(int row, int count, const QModelIndex& parent) 0161 { 0162 if (row < 0 or row + count - 1 >= rowCount()) 0163 return false; 0164 0165 beginRemoveRows(parent, row, row + count - 1); 0166 0167 for (int i = 0; i < count; i++) { 0168 m_sessionList.removeAt(row); 0169 } 0170 0171 endRemoveRows(); 0172 0173 return true; 0174 } 0175 0176 void SessionModel::append(const Session& session) 0177 { 0178 beginInsertRows(QModelIndex(), rowCount(), rowCount()); // i.e. append the new row at the table end 0179 m_sessionList.append(session); 0180 endInsertRows(); 0181 } 0182 0183 void SessionModel::update(const Session& session) 0184 { 0185 int i = m_sessionList.indexOf(session); 0186 0187 if (i == -1) 0188 return; 0189 0190 m_sessionList[i] = session; 0191 m_sessionList[i].setDate(QDateTime::currentDateTime()); 0192 0193 emit dataChanged({}, {}); 0194 } 0195 0196 bool SessionModel::isEmpty() const 0197 { 0198 return m_sessionList.isEmpty(); 0199 } 0200 0201 bool SessionModel::isEditable(const QModelIndex& index) const 0202 { 0203 auto role = roleForColumn(index.column()); 0204 return role == Roles::NameRole or role == Roles::NoteRole; 0205 } 0206 0207 void SessionModel::read(const QJsonObject& json) 0208 { 0209 const auto sessions = json[QStringLiteral("sessions")].toArray(); 0210 for (const auto& session : sessions) { 0211 append(Session::fromJson(session.toObject())); 0212 } 0213 } 0214 0215 void SessionModel::slotWriteData() 0216 { 0217 QFile saveFile {QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QLatin1String("/sessions.json")}; 0218 if (not saveFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { 0219 qDebug().nospace() << "cannot open " << saveFile.fileName() << ": " << saveFile.errorString(); 0220 return; 0221 } 0222 0223 auto json = QJsonObject {}; 0224 json[QStringLiteral("sessions")] = jsonSessions(); 0225 0226 auto saveDoc = QJsonDocument {json}; 0227 saveFile.write(saveDoc.toJson()); 0228 } 0229 0230 int SessionModel::columnForRole(SessionModel::Roles role) const 0231 { 0232 return m_roles.indexOf(role); 0233 } 0234 0235 SessionModel::Roles SessionModel::roleForColumn(int column) const 0236 { 0237 return m_roles.at(column); 0238 } 0239 0240 QJsonArray SessionModel::jsonSessions() const 0241 { 0242 auto array = QJsonArray {}; 0243 const auto sessions = m_sessionList; 0244 for (const auto& session : sessions) { 0245 auto object = QJsonObject {}; 0246 session.write(object); 0247 array.append(object); 0248 } 0249 0250 return array; 0251 } 0252