File indexing completed on 2024-05-05 17:04:25

0001 /* This file is part of the KDE project
0002  * Copyright 2014  Dan Leinir Turthra Jensen <admin@leinir.dk>
0003  *
0004  * This program is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU General Public License as
0006  * published by the Free Software Foundation; either version 2 of
0007  * the License or (at your option) version 3 or any later version
0008  * accepted by the membership of KDE e.V. (or its successor approved
0009  * by the membership of KDE e.V.), which shall act as a proxy
0010  * defined in Section 14 of version 3 of the license.
0011  *
0012  * This program is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015  * GNU General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU General Public License
0018  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0019  *
0020  */
0021 
0022 #include "CloudAccountsModel.h"
0023 #include "PropertyContainer.h"
0024 
0025 #include <QDebug>
0026 #include <QByteArray>
0027 #include <QDataStream>
0028 #include <QVariant>
0029 #include <QMetaObject>
0030 #include <QMetaProperty>
0031 #include <QFile>
0032 #include <QStandardPaths>
0033 
0034 struct AccountEntry {
0035 public:
0036     AccountEntry(QObject* parent)
0037         : selected(false)
0038         , accountDetails(new PropertyContainer("", parent))
0039     {}
0040     QString text;
0041     bool selected;
0042     QString accountType;
0043     QString stackComponent;
0044     QObject* accountDetails;
0045 
0046     QByteArray serialize() {
0047         // selected is not serialised, because that would be silly
0048         QByteArray ba;
0049         QDataStream stream(&ba, QIODevice::WriteOnly);
0050         stream << text;
0051         stream << accountType;
0052         stream << stackComponent;
0053         Q_FOREACH(const QByteArray &name, accountDetails->dynamicPropertyNames()) {
0054             stream << name << accountDetails->property(name);
0055         }
0056         for(int i = accountDetails->metaObject()->propertyOffset(); i < accountDetails->metaObject()->propertyCount(); ++i) {
0057             stream << accountDetails->metaObject()->property(i).name() << accountDetails->metaObject()->property(i).read(accountDetails);
0058         }
0059         return ba;
0060     }
0061 
0062     static AccountEntry* fromByteArray(QByteArray& ba, QObject* parent) {
0063         AccountEntry* entry = new AccountEntry(parent);
0064         QDataStream stream(&ba, QIODevice::ReadOnly);
0065         stream >> entry->text;
0066         stream >> entry->accountType;
0067         stream >> entry->stackComponent;
0068         entry->accountDetails->setProperty("text", entry->text);
0069         while(!stream.atEnd()) {
0070             QByteArray propertyName;
0071             QVariant data;
0072             stream >> propertyName;
0073             stream >> data;
0074             entry->accountDetails->setProperty(propertyName, data);
0075         }
0076         return entry;
0077     }
0078 };
0079 
0080 class CloudAccountsModel::Private {
0081 public:
0082     Private(CloudAccountsModel* qq)
0083         : q(qq)
0084     {
0085         dataFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/calligrageminicloudaccounts");
0086         loadList();
0087     }
0088     ~Private()
0089     {
0090         qDeleteAll(entries);
0091     }
0092     CloudAccountsModel* q;
0093     QList<AccountEntry*> entries;
0094     QString dataFile;
0095 
0096     void saveList()
0097     {
0098         QByteArray ba;
0099         QDataStream stream(&ba, QIODevice::WriteOnly);
0100         Q_FOREACH(AccountEntry* entry, entries) {
0101             stream << entry->serialize();
0102         }
0103         QFile data(dataFile);
0104         data.open(QIODevice::WriteOnly);
0105         data.write(ba);
0106         data.close();
0107     }
0108 
0109     void loadList()
0110     {
0111         QByteArray ba;
0112         QFile data(dataFile);
0113         data.open(QIODevice::ReadOnly);
0114         ba = data.readAll();
0115         data.close();
0116 
0117         q->beginResetModel();
0118         qDeleteAll(entries);
0119         entries.clear();
0120 
0121         QDataStream stream(&ba, QIODevice::ReadOnly);
0122         QByteArray entryBA;
0123         while(!stream.atEnd()) {
0124             stream >> entryBA;
0125             entries.append(AccountEntry::fromByteArray(entryBA, q));
0126         }
0127 
0128         q->endResetModel();
0129     }
0130 };
0131 
0132 CloudAccountsModel::CloudAccountsModel(QObject* parent)
0133     : QAbstractListModel(parent)
0134     , d(new Private(this))
0135 {
0136     QHash<int, QByteArray> roles;
0137     roles[TextRole] = "text";
0138     roles[SelectedRole] = "selected";
0139     roles[AccountTypeRole] = "accountType";
0140     roles[StackComponentRole] = "stackComponent";
0141     roles[AccountDetailsRole] = "accountDetails";
0142     setRoleNames(roles);
0143 }
0144 
0145 CloudAccountsModel::~CloudAccountsModel()
0146 {
0147     delete d;
0148 }
0149 
0150 QVariant CloudAccountsModel::data(const QModelIndex& index, int role) const
0151 {
0152     QVariant result;
0153     if(index.isValid() && index.row() > -1 && index.row() < d->entries.count())
0154     {
0155         AccountEntry* entry = d->entries.at(index.row());
0156         switch(role)
0157         {
0158             case TextRole:
0159                 result = entry->text;
0160                 break;
0161             case SelectedRole:
0162                 result = entry->selected;
0163                 break;
0164             case AccountTypeRole:
0165                 result = entry->accountType;
0166                 break;
0167             case StackComponentRole:
0168                 result = entry->stackComponent;
0169                 break;
0170             case AccountDetailsRole:
0171                 result = QVariant::fromValue<QObject*>(entry->accountDetails);
0172                 break;
0173             default:
0174                 break;
0175         }
0176     }
0177     return result;
0178 }
0179 
0180 int CloudAccountsModel::rowCount(const QModelIndex& parent) const
0181 {
0182     if(parent.isValid())
0183         return 0;
0184     return d->entries.count();
0185 }
0186 
0187 void CloudAccountsModel::selectIndex(int newSelection)
0188 {
0189     Q_FOREACH(AccountEntry* entry, d->entries) {
0190         entry->selected = false;
0191     }
0192     if(newSelection >= 0 && newSelection < d->entries.count()) {
0193         d->entries.at(newSelection)->selected = true;
0194     }
0195     dataChanged(index(0), index(d->entries.count() - 1));
0196 }
0197 
0198 void CloudAccountsModel::addAccount(QString text, QString accountType, QString stackComponent, QObject* accountDetails, bool removeExisting)
0199 {
0200     if(removeExisting) {
0201         removeAccountByName(text);
0202     }
0203     AccountEntry* entry = new AccountEntry(this);
0204     entry->text = text;
0205     entry->accountType = accountType;
0206     entry->stackComponent = stackComponent;
0207     if(accountDetails) {
0208         Q_FOREACH(const QByteArray &name, accountDetails->dynamicPropertyNames()) {
0209             entry->accountDetails->setProperty(name, accountDetails->property(name));
0210         }
0211         for(int i = accountDetails->metaObject()->propertyOffset(); i < accountDetails->metaObject()->propertyCount(); ++i) {
0212             entry->accountDetails->setProperty(accountDetails->metaObject()->property(i).name(), accountDetails->metaObject()->property(i).read(accountDetails));
0213         }
0214     }
0215     int count = d->entries.count();
0216     beginInsertRows(QModelIndex(), count, count);
0217     d->entries.append(entry);
0218     endInsertRows();
0219     d->saveList();
0220 }
0221 
0222 void CloudAccountsModel::renameAccount(int index, QString newText)
0223 {
0224     if(index > -1 && index < d->entries.count() - 1)
0225     {
0226         d->entries.at(index)->text = newText;
0227         dataChanged(this->index(index), this->index(index));
0228         d->saveList();
0229     }
0230 }
0231 
0232 void CloudAccountsModel::removeAccountByName(QString text)
0233 {
0234     beginResetModel();
0235     for(int i = d->entries.count() - 1; i > -1; --i) {
0236         if(d->entries.at(i)->text == text) {
0237             d->entries.removeAt(i);
0238         }
0239     }
0240     endResetModel();
0241 }
0242 
0243 void CloudAccountsModel::removeAccount(int index)
0244 {
0245     if(index > -1 && index < d->entries.count())
0246     {
0247         beginRemoveRows(QModelIndex(), index, index);
0248         delete(d->entries.takeAt(index));
0249         endRemoveRows();
0250         d->saveList();
0251     }
0252 }
0253 
0254 QObject* CloudAccountsModel::accountDetails(int index)
0255 {
0256     if(index > -1 && index < d->entries.count() - 1)
0257     {
0258         return d->entries.at(index)->accountDetails;
0259     }
0260     return 0;
0261 }
0262 
0263 void CloudAccountsModel::setAccountDetails(int index, QObject* newDetails)
0264 {
0265     if(index > -1 && index < d->entries.count() - 1)
0266     {
0267         AccountEntry* entry = d->entries.at(index);
0268         if(newDetails) {
0269             Q_FOREACH(const QByteArray &name, newDetails->dynamicPropertyNames()) {
0270                 entry->accountDetails->setProperty(name, newDetails->property(name));
0271             }
0272             for(int i = newDetails->metaObject()->propertyOffset(); i < newDetails->metaObject()->propertyCount(); ++i) {
0273                 entry->accountDetails->setProperty(newDetails->metaObject()->property(i).name(), newDetails->metaObject()->property(i).read(newDetails));
0274             }
0275         }
0276         d->saveList();
0277     }
0278 }