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