346 lines
9.5 KiB
C++
346 lines
9.5 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
*
|
|
* Copyright (C) 2013 - 2024, nymea GmbH
|
|
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
|
*
|
|
* This file is part of nymea-app.
|
|
*
|
|
* nymea-app is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* nymea-app is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with nymea-app. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include "configuredhostsmodel.h"
|
|
|
|
#include <QDir>
|
|
#include <QSettings>
|
|
#include <QStandardPaths>
|
|
#include <QRegularExpression>
|
|
|
|
#include <QLoggingCategory>
|
|
Q_DECLARE_LOGGING_CATEGORY(dcApplication)
|
|
|
|
ConfiguredHostsModel::ConfiguredHostsModel(QObject *parent) : QAbstractListModel(parent)
|
|
{
|
|
QSettings settings;
|
|
settings.beginGroup("ConfiguredHosts");
|
|
foreach (const QString &childGroup, settings.childGroups()) {
|
|
settings.beginGroup(childGroup);
|
|
QUuid uuid = settings.value("uuid").toUuid();
|
|
QString cachedName = settings.value("cachedName").toString();
|
|
ConfiguredHost *host = new ConfiguredHost(uuid, this);
|
|
host->setName(cachedName);
|
|
addHost(host);
|
|
settings.endGroup();
|
|
}
|
|
m_currentIndex = settings.value("currentIndex", 0).toInt();
|
|
settings.endGroup();
|
|
|
|
// There must be always 1 at least
|
|
if (m_list.isEmpty()) {
|
|
createHost();
|
|
}
|
|
|
|
// Make sure the currentIndex from the config isn't out of place
|
|
if (m_currentIndex >= m_list.count()) {
|
|
m_currentIndex = static_cast<int>(m_list.count()) - 1;
|
|
}
|
|
}
|
|
|
|
int ConfiguredHostsModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
Q_UNUSED(parent)
|
|
return static_cast<int>(m_list.count());
|
|
}
|
|
|
|
QVariant ConfiguredHostsModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
switch (role) {
|
|
case RoleUuid:
|
|
return m_list.at(index.row())->uuid();
|
|
case RoleName:
|
|
if (!m_list.at(index.row())->name().isEmpty()) {
|
|
return m_list.at(index.row())->name();
|
|
}
|
|
return m_list.at(index.row())->uuid();
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
QHash<int, QByteArray> ConfiguredHostsModel::roleNames() const
|
|
{
|
|
QHash<int, QByteArray> roles;
|
|
roles.insert(RoleUuid, "uuid");
|
|
roles.insert(RoleName, "name");
|
|
return roles;
|
|
}
|
|
|
|
ConfiguredHost *ConfiguredHostsModel::get(int index) const
|
|
{
|
|
if (index < 0 || index >= m_list.count()) {
|
|
return nullptr;
|
|
}
|
|
return m_list.at(index);
|
|
}
|
|
|
|
int ConfiguredHostsModel::currentIndex() const
|
|
{
|
|
return m_currentIndex;
|
|
}
|
|
|
|
void ConfiguredHostsModel::setCurrentIndex(int currentIndex)
|
|
{
|
|
if (m_currentIndex != currentIndex) {
|
|
m_currentIndex = currentIndex;
|
|
emit currentIndexChanged();
|
|
|
|
QSettings settings;
|
|
settings.beginGroup("ConfiguredHosts");
|
|
settings.setValue("currentIndex", currentIndex);
|
|
settings.endGroup();
|
|
}
|
|
}
|
|
|
|
ConfiguredHost *ConfiguredHostsModel::createHost()
|
|
{
|
|
ConfiguredHost *host = new ConfiguredHost();
|
|
addHost(host);
|
|
return host;
|
|
}
|
|
|
|
void ConfiguredHostsModel::removeHost(int index)
|
|
{
|
|
if (index < 0 || index >= m_list.count()) {
|
|
qCWarning(dcApplication()) << "Cannot remove connection at index" << index;
|
|
return;
|
|
}
|
|
|
|
beginRemoveRows(QModelIndex(), index, index);
|
|
|
|
ConfiguredHost *host = m_list.takeAt(index);
|
|
qCDebug(dcApplication()) << "Remove configured host" << host->name() << host->uuid().toString();
|
|
|
|
QSettings settings;
|
|
|
|
QString hostUuidString = host->uuid().toString();
|
|
|
|
qCDebug(dcApplication()) << "-> Remove stored token";
|
|
settings.beginGroup("jsonTokens");
|
|
if (settings.contains(hostUuidString)) {
|
|
settings.remove(hostUuidString);
|
|
}
|
|
settings.endGroup();
|
|
|
|
qCDebug(dcApplication()) << "-> Remove cached hosts";
|
|
settings.beginGroup("HostCache");
|
|
settings.beginGroup(hostUuidString);
|
|
settings.remove("");
|
|
settings.endGroup();
|
|
settings.endGroup();
|
|
|
|
qCDebug(dcApplication()) << "-> Remove host settings";
|
|
settings.beginGroup(hostUuidString);
|
|
settings.remove("");
|
|
settings.endGroup();
|
|
|
|
QDir dir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/sslcerts/");
|
|
QFile certFile(dir.absoluteFilePath(hostUuidString.remove(QRegularExpression("[{}]")) + ".pem"));
|
|
if (certFile.exists()) {
|
|
if (!certFile.remove()) {
|
|
qCWarning(dcApplication()) << "Failed to remove certificate file" << certFile.fileName() << certFile.errorString();
|
|
} else {
|
|
qCDebug(dcApplication()) << "-> Removed successfully host certificate" << certFile.fileName();
|
|
}
|
|
} else {
|
|
qCDebug(dcApplication()) << "-> No certificated stored for this host";
|
|
}
|
|
|
|
host->deleteLater();
|
|
|
|
saveToDisk();
|
|
|
|
endRemoveRows();
|
|
emit countChanged();
|
|
|
|
|
|
if (m_list.isEmpty()) {
|
|
createHost();
|
|
}
|
|
|
|
if (m_currentIndex >= m_list.count()) {
|
|
m_currentIndex = static_cast<int>(m_list.count()) - 1;
|
|
emit currentIndexChanged();
|
|
}
|
|
}
|
|
|
|
void ConfiguredHostsModel::move(int from, int to)
|
|
{
|
|
// QList's and QAbstractItemModel's move implementation differ when moving an item up the list :/
|
|
// While QList needs the index in the resulting list, beginMoveRows expects it to be in the current list
|
|
// adjust the model's index by +1 in case we're moving upwards
|
|
int newModelIndex = to > from ? to+1 : to;
|
|
|
|
qWarning() << "from:" << from << "to" << to << "modelTo" << newModelIndex;
|
|
beginMoveRows(QModelIndex(), from, from, QModelIndex(), newModelIndex);
|
|
m_list.move(from, to);
|
|
saveToDisk();
|
|
endMoveRows();
|
|
}
|
|
|
|
int ConfiguredHostsModel::indexOf(ConfiguredHost *host) const
|
|
{
|
|
return static_cast<int>(static_cast<int>(m_list.indexOf(host)));
|
|
}
|
|
|
|
void ConfiguredHostsModel::addHost(ConfiguredHost *host)
|
|
{
|
|
host->setParent(this);
|
|
const int insertPos = static_cast<int>(m_list.count());
|
|
beginInsertRows(QModelIndex(), insertPos, insertPos);
|
|
connect(host->engine()->jsonRpcClient(), &JsonRpcClient::currentHostChanged, this, [=]{
|
|
if (host->engine()->jsonRpcClient()->currentHost()) {
|
|
host->setUuid(host->engine()->jsonRpcClient()->currentHost()->uuid());
|
|
} else {
|
|
host->setUuid(QUuid());
|
|
host->setName(QString());
|
|
}
|
|
saveToDisk();
|
|
});
|
|
connect(host->engine()->jsonRpcClient(), &JsonRpcClient::serverNameChanged, this, [=]{
|
|
host->setName(host->engine()->jsonRpcClient()->serverName());
|
|
saveToDisk();
|
|
});
|
|
connect(host, &ConfiguredHost::nameChanged, this, [=](){
|
|
QModelIndex idx = index(static_cast<int>(static_cast<int>(m_list.indexOf(host))));
|
|
emit dataChanged(idx, idx, {RoleName});
|
|
});
|
|
connect(host, &ConfiguredHost::uuidChanged, this, [=](){
|
|
saveToDisk();
|
|
});
|
|
m_list.append(host);
|
|
endInsertRows();
|
|
emit countChanged();
|
|
}
|
|
|
|
void ConfiguredHostsModel::saveToDisk()
|
|
{
|
|
QSettings settings;
|
|
settings.beginGroup("ConfiguredHosts");
|
|
settings.remove("");
|
|
settings.setValue("currentIndex", m_currentIndex);
|
|
for (int i = 0; i < m_list.count(); i++) {
|
|
settings.beginGroup(QString::number(i));
|
|
settings.setValue("uuid", m_list.at(i)->uuid());
|
|
settings.setValue("cachedName", m_list.at(i)->name());
|
|
settings.endGroup();
|
|
}
|
|
settings.endGroup();
|
|
}
|
|
|
|
ConfiguredHost::ConfiguredHost(const QUuid &uuid, QObject *parent):
|
|
QObject(parent),
|
|
m_uuid(uuid),
|
|
m_engine(new Engine(this))
|
|
{
|
|
|
|
}
|
|
|
|
QUuid ConfiguredHost::uuid() const
|
|
{
|
|
return m_uuid;
|
|
}
|
|
|
|
void ConfiguredHost::setUuid(const QUuid &uuid)
|
|
{
|
|
if (m_uuid != uuid) {
|
|
m_uuid = uuid;
|
|
emit uuidChanged();
|
|
}
|
|
}
|
|
|
|
Engine *ConfiguredHost::engine() const
|
|
{
|
|
return m_engine;
|
|
}
|
|
|
|
QString ConfiguredHost::name() const
|
|
{
|
|
return m_name;
|
|
}
|
|
|
|
void ConfiguredHost::setName(const QString &name)
|
|
{
|
|
if (m_name != name) {
|
|
m_name = name;
|
|
emit nameChanged();
|
|
}
|
|
}
|
|
|
|
ConfiguredHostsProxyModel::ConfiguredHostsProxyModel(QObject *parent):
|
|
QSortFilterProxyModel(parent)
|
|
{
|
|
|
|
}
|
|
|
|
ConfiguredHostsModel *ConfiguredHostsProxyModel::model() const
|
|
{
|
|
return m_model;
|
|
}
|
|
|
|
void ConfiguredHostsProxyModel::setModel(ConfiguredHostsModel *model)
|
|
{
|
|
if (m_model != model) {
|
|
m_model = model;
|
|
emit modelChanged();
|
|
|
|
setSourceModel(model);
|
|
sort(0);
|
|
}
|
|
}
|
|
|
|
QUuid ConfiguredHostsProxyModel::currentHost() const
|
|
{
|
|
return m_currentHost;
|
|
}
|
|
|
|
void ConfiguredHostsProxyModel::setCurrentHost(const QUuid ¤tHost)
|
|
{
|
|
if (m_currentHost != currentHost) {
|
|
m_currentHost = currentHost;
|
|
emit currentHostChanged();
|
|
|
|
invalidate();
|
|
}
|
|
}
|
|
|
|
ConfiguredHost *ConfiguredHostsProxyModel::get(int index) const
|
|
{
|
|
return m_model->get(mapToSource(this->index(index, 0)).row());
|
|
}
|
|
|
|
bool ConfiguredHostsProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
|
{
|
|
ConfiguredHost *left = m_model->get(source_left.row());
|
|
ConfiguredHost *right = m_model->get(source_right.row());
|
|
|
|
if (left->uuid() == m_currentHost) {
|
|
return true;
|
|
}
|
|
if (right->uuid() == m_currentHost) {
|
|
return false;
|
|
}
|
|
return source_left.row() < source_right.row();
|
|
}
|