Commit fd56088e authored by Viktor Porvaznik's avatar Viktor Porvaznik Committed by Viktor Porvaznik

More work on Dbus

parent 3cf51e78
......@@ -2,7 +2,9 @@ qt5_add_resources(KDECONNECT_FILESYNC_CLIENT_SRCS resources.qrc)
add_executable(kdeconnect-filesync-client
main.cpp
${KDECONNECT_FILESYNC_CLIENT_SRCS})
sync_table_model.cpp
../../filesyncapp/interfaces/json_types.cpp
${KDECONNECT_FILESYNC_CLIENT_SRCS} sync_table_model.cpp sync_table_model.h)
target_link_libraries(kdeconnect-filesync-client
kdeconnectinterfaces
......
/**
* Copyright 2019 Viktor Porvaznik <viktor.porvaznik@piceacode.eu>
*
* This program 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 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config_dialog.h"
#include <KPluginFactory>
#include <QTableView>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QPushButton>
#include <QMenu>
#include <QStandardItemModel>
#include <QDebug>
#include <QUuid>
#include <QJsonDocument>
#include <QJsonArray>
#include <KLocalizedString>
#include <QLoggingCategory>
#include <core/dbushelper.h>
K_PLUGIN_FACTORY(SyncConfigFactory, registerPlugin<SyncPlugin::ConfigDialog>();)
Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_SYNC, "kdeconnect.plugin.sync")
SyncPlugin::ConfigDialog::ConfigDialog(QWidget *parent,
const QVariantList &args)
: KdeConnectPluginKcm(parent, args,
QStringLiteral("kdeconnect_sync_config"))
{
QTableView *table = new QTableView(this);
table->horizontalHeader()->setStretchLastSection(true);
table->verticalHeader()->setVisible(false);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(table);
QPushButton *button;
button = new QPushButton(QIcon::fromTheme(QStringLiteral("list-remove")),
i18n("Remove sync entry"), this);
layout->addWidget(button);
setLayout(layout);
m_entriesModel = new QStandardItemModel(this);
table->setModel(m_entriesModel);
m_entriesModel->setHorizontalHeaderLabels(
QStringList() << i18n("Remote path") << i18n("Local path")
<< i18n("Post sync script"));
}
SyncPlugin::ConfigDialog::~ConfigDialog()
{
}
void SyncPlugin::ConfigDialog::defaults()
{
KCModule::defaults();
m_entriesModel->clear();
Q_EMIT changed(true);
}
void SyncPlugin::ConfigDialog::load()
{
KCModule::load();
QJsonDocument jsonDocument = QJsonDocument::fromJson(
config()->get<QByteArray>(QStringLiteral("syncEntries"), "{}"));
QJsonObject jsonConfig = jsonDocument.object();
const QStringList keys = jsonConfig.keys();
for (const QString &key : keys)
{
const QJsonObject entry = jsonConfig[key].toObject();
const QString remotePath = entry[QStringLiteral("remotePath")].toString();
const QString localPath = entry[QStringLiteral("localPath")].toString();
const QString postSyncScript = entry[QStringLiteral(
"postSyncScript")].toString();
QStandardItem *newRemotePath = new QStandardItem(remotePath);
newRemotePath->setEditable(true);
QStandardItem *newLocalPath = new QStandardItem(localPath);
newLocalPath->setEditable(true);
QStandardItem *newPostSyncScript = new QStandardItem(postSyncScript);
newPostSyncScript->setEditable(true);
m_entriesModel->appendRow(
QList<QStandardItem *>() << newRemotePath << newLocalPath
<< newPostSyncScript);
}
m_entriesModel->sort(0);
insertEmptyRow();
connect(m_entriesModel, &QAbstractItemModel::dataChanged, this,
&ConfigDialog::onDataChanged);
Q_EMIT changed(false);
}
void SyncPlugin::ConfigDialog::save()
{
QJsonObject jsonConfig;
for (int i = 0; i < m_entriesModel->rowCount(); i++)
{
QString key = QUuid::createUuid().toString();
DbusHelper::filterNonExportableCharacters(key);
const QString remotePath = m_entriesModel->item(i, 0)->text();
const QString localPath = m_entriesModel->item(i, 1)->text();
const QString postSyncScript = m_entriesModel->item(i, 2)->text();
if (remotePath.isEmpty() || localPath.isEmpty())
{
continue;
}
QJsonObject entry;
entry[QStringLiteral("remotePath")] = remotePath;
entry[QStringLiteral("localPath")] = localPath;
entry[QStringLiteral("postSyncScript")] = postSyncScript;
jsonConfig[key] = entry;
}
QJsonDocument document;
document.setObject(jsonConfig);
config()->set(QStringLiteral("syncEntries"),
document.toJson(QJsonDocument::Compact));
KCModule::save();
Q_EMIT changed(false);
}
void SyncPlugin::ConfigDialog::onDataChanged(const QModelIndex &topLeft,
const QModelIndex &bottomRight)
{
Q_EMIT changed(true);
Q_UNUSED(topLeft);
if (bottomRight.row() == m_entriesModel->rowCount() - 1)
{
insertEmptyRow();
}
}
void SyncPlugin::ConfigDialog::insertRow(int i, const QString &remotePath,
const QString &localPath,
const QString &postSyncScript)
{
QStandardItem *newRemotePath = new QStandardItem(remotePath);
newRemotePath->setEditable(true);
QStandardItem *newLocalPath = new QStandardItem(localPath);
newLocalPath->setEditable(true);
QStandardItem *newPostSyncScript = new QStandardItem(postSyncScript);
newPostSyncScript->setEditable(true);
m_entriesModel->insertRow(i, QList<QStandardItem *>() << newRemotePath
<< newLocalPath
<< newPostSyncScript);
}
void SyncPlugin::ConfigDialog::insertEmptyRow()
{
insertRow(m_entriesModel->rowCount(), {}, {}, {});
}
#include "config_dialog.moc"
......@@ -22,196 +22,13 @@
#include <QQmlApplicationEngine>
#include <QCommandLineParser>
#include <QApplication>
#include <QStandardItemModel>
#include <KAboutData>
#include <KLocalizedString>
#include <QDBusPendingReply>
#include <KLocalizedContext>
#include <KDBusService>
#include <QtQml>
#include "interfaces/dbusinterfaces.h"
class TableModel : public QAbstractTableModel
{
Q_OBJECT
private:
QJsonArray m_data;
static const QStringList s_syncTableColumns;
public:
TableModel() {
loadModel();
qDebug() << m_data << endl;
}
TableModel(const QJsonArray& data) : m_data(data) {
m_data = data;
qDebug() << m_data << endl;
}
int rowCount(const QModelIndex & = QModelIndex()) const override
{
return m_data.size();
}
//
// QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override
// {
// qDebug() << "header called" << endl;
// switch (role) {
// case Qt::DisplayRole:
// {
// return QString("test header");
// }
// default:
// break;
// }
//
// return QVariant();
// }
int columnCount(const QModelIndex & = QModelIndex()) const override
{
return s_syncTableColumns.size();
}
QVariant data(const QModelIndex &index, int role) const override
{
qDebug() << " Item at " << index.row() << ";" << index.column() << ";" << role << endl;
return m_data.at(index.row()).toObject().value(s_syncTableColumns[(role - Qt::UserRole)]);
// switch (role) {
// case (Qt::UserRole + 1):
// {
// return m_data.at(index.row()).toObject().value(s_syncTableColumns[0]);
// }
// case (Qt::UserRole + 2):
// {
// QJsonObject row = m_data.at(index.row()).toObject();
// qDebug() << s_syncTableColumns.value(index.column()) << endl;
// qDebug() << row[s_syncTableColumns.value(index.column())].toString() << endl;
// return m_data.at(index.row()).toObject().value(s_syncTableColumns[1]);
// }
// default:
// break;
// }
// return QVariant();
}
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
{
QJsonObject newObject = m_data.at(index.row()).toObject();
newObject.insert(s_syncTableColumns[(role - Qt::UserRole)], value.toString());
m_data.replace(index.row(), newObject);
saveModel(m_data);
qDebug() << " SetData at " << index.row() << ";" << index.column() << ";" << role << value << endl;
switch (role) {
case Qt::EditRole:
qDebug() << value << endl;
default:
break;
}
Q_EMIT dataChanged(index, index, QVector<int>(role));
return true;
}
QHash<int, QByteArray> roleNames() const override
{
QHash<int, QByteArray> roleNames;
for (int i = 0; i < s_syncTableColumns.size(); i++)
{
roleNames.insert((Qt::UserRole + i), s_syncTableColumns[i].toLatin1());
}
return roleNames;
}
public Q_SLOTS:
bool insertADefaultRow()
{
loadModel();
bool retValue = insertRows(rowCount(), 1);
saveModel(m_data);
return retValue;
};
bool removeSelectedRow(int row)
{
bool retValue = removeRows(row, 1);
saveModel(m_data);
return retValue;
};
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex())
{
beginRemoveRows(parent, row, row + (count - 1));
m_data.removeAt(row);
endRemoveRows();
return true;
};
bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())
{
beginInsertRows(parent, row, row + (count - 1));
QJsonObject rowData;
rowData.insert("localPath", "");
rowData.insert("remotePath", "");
rowData.insert("direction", "DEFAULT");
rowData.insert("postSyncScript", "");
m_data.append(rowData);
endInsertRows();
return true;
};
void addSyncItem(const QString &localPath, const QString &remotePath, const QString &direction, const QString &postSyncScript)
{
QJsonObject row;
row.insert("localPath", localPath);
row.insert("remotePath", remotePath);
row.insert("direction", direction);
row.insert("postSyncScript", postSyncScript);
m_data.append(row);
qDebug() << m_data << endl;
}
void saveModel(const QJsonArray& model)
{
qDebug() << model << endl;
}
void loadModel()
{
qDebug() << "Loading model" << endl;
FileSyncAppInterface *fileSyncAppInterface = new FileSyncAppInterface(this);
QDBusPendingReply<QVariantList> reply = fileSyncAppInterface->getConfiguration();
reply.waitForFinished();
if (reply.isValid())
{
QVariantList result = reply.value();
// QDBusVariant dbusVariant = qvariant_cast<QDBusVariant>(reply.value());
// QVariant result2 = dbusVariant.variant();
qDebug() << "Loaded model" << result << endl;
// retrieve the D-Bus variant
// retrieve the actual value stored in the D-Bus variant
// m_data = QJsonArray::fromVariantList(reply.value());
}
qDebug() << "Loaded model" << endl;
qDebug() << m_data << endl;
}
};
const QStringList TableModel::s_syncTableColumns = QStringList({"localPath", "remotePath", "direction", "postSyncScript"});
//#include "filesyncapp/interfaces/json_types.h"
#include "sync_table_model.h"
int main(int argc, char *argv[])
{
// FileSync::JsonTypes::registerQJsonArrayTypeAsDbusType();
// FileSync::JsonTypes::registerQJsonObjectTypeAsDbusType();
QApplication app(argc, argv);
QApplication::setApplicationName("KDE Connect File Synchronization Client");
QApplication::setApplicationVersion("0.1.0");
......@@ -224,7 +41,7 @@ int main(int argc, char *argv[])
TableModel *syncTableModel = new TableModel();
FileSync::SyncTableModel *syncTableModel = new FileSync::SyncTableModel();
// syncTableModel->addSyncItem("test1", "test2", "ONLY_DOWNLOAD", "test3");
// syncTableModel->addSyncItem("t22est1", "te222st2", "NEWEST", "te2333st3");
// QStandardItemModel syncTableModel(1,1,&app);
......
/**
* Copyright 2019 Viktor Porvaznik <viktor.porvaznik@gmail.com>
*
* This program 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 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "sync_table_model.h"
#include "../../filesyncapp/interfaces/json_types.h"
const QStringList FileSync::SyncTableModel::s_syncTableColumns = QStringList({"localPath", "remotePath", "direction", "postSyncScript"});
void FileSync::SyncTableModel::loadModel()
{
qDebug() << "Loading model" << endl;
FileSyncAppInterface *fileSyncAppInterface = new FileSyncAppInterface(this);
QDBusPendingReply<QVariantList> reply = fileSyncAppInterface->getConfiguration("testDevice");
reply.waitForFinished();
if (reply.isValid())
{
m_data = FileSync::JsonTypes::convertQVariantListToQJsonArray(reply.value());
}
else
{
qDebug() << "err " << reply.error() << endl;
}
qDebug() << "Loaded model" << endl;
qDebug() << m_data << endl;
}
void FileSync::SyncTableModel::saveModel(const QJsonArray &model)
{
qDebug() << "saving " << endl;
QVariantList variantList;
for (const QJsonValue &value : m_data) {
variantList.append(value.toObject());
}
FileSyncAppInterface *fileSyncAppInterface = new FileSyncAppInterface(this);
QDBusPendingReply<bool> reply = fileSyncAppInterface->setConfiguration(variantList);
reply.waitForFinished();
if (reply.isValid())
{
qDebug() << "ok " << reply.value() << endl;
}
else
{
qDebug() << "err " << reply.error() << endl;
}
qDebug() << "Loaded model" << endl;
}
/**
* Copyright 2019 Viktor Porvaznik <viktor.porvaznik@gmail.com>
*
* This program 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 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KDECONNECT_SYNC_TABLE_MODEL_H
#define KDECONNECT_SYNC_TABLE_MODEL_H
#include <QStandardItemModel>
#include <KAboutData>
#include <KLocalizedString>
#include <QDBusPendingReply>
#include <KLocalizedContext>
#include <KDBusService>
#include <QtQml>
#include "interfaces/dbusinterfaces.h"
namespace FileSync {
class SyncTableModel : public QAbstractTableModel
{
Q_OBJECT
private:
QJsonArray m_data;
static const QStringList s_syncTableColumns;
public:
SyncTableModel() {
loadModel();
qDebug() << m_data << endl;
}
SyncTableModel(const QJsonArray& data) : m_data(data) {
m_data = data;
qDebug() << m_data << endl;
}
int rowCount(const QModelIndex & = QModelIndex()) const override
{
return m_data.size();
}
//
// QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override
// {
// qDebug() << "header called" << endl;
// switch (role) {
// case Qt::DisplayRole:
// {
// return QString("test header");
// }
// default:
// break;
// }
//
// return QVariant();
// }
int columnCount(const QModelIndex & = QModelIndex()) const override
{
return s_syncTableColumns.size();
}
QVariant data(const QModelIndex &index, int role) const override
{
qDebug() << " Item at " << index.row() << ";" << index.column() << ";" << role << endl;
return m_data.at(index.row()).toObject().value(s_syncTableColumns[(role - Qt::UserRole)]);
// switch (role) {
// case (Qt::UserRole + 1):
// {
// return m_data.at(index.row()).toObject().value(s_syncTableColumns[0]);
// }
// case (Qt::UserRole + 2):
// {
// QJsonObject row = m_data.at(index.row()).toObject();
// qDebug() << s_syncTableColumns.value(index.column()) << endl;
// qDebug() << row[s_syncTableColumns.value(index.column())].toString() << endl;
// return m_data.at(index.row()).toObject().value(s_syncTableColumns[1]);
// }
// default:
// break;
// }
// return QVariant();
}
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
{
QJsonObject newObject = m_data.at(index.row()).toObject();
newObject.insert(s_syncTableColumns[(role - Qt::UserRole)], value.toString());
m_data.replace(index.row(), newObject);
saveModel(m_data);
qDebug() << " SetData at " << index.row() << ";" << index.column() << ";" << role << value << endl;
switch (role) {
case Qt::EditRole:
qDebug() << value << endl;
default:
break;
}
Q_EMIT dataChanged(index, index, QVector<int>(role));
return true;
}
QHash<int, QByteArray> roleNames() const override
{
QHash<int, QByteArray> roleNames;
for (int i = 0; i < s_syncTableColumns.size(); i++)
{
roleNames.insert((Qt::UserRole + i), s_syncTableColumns[i].toLatin1());
}
return roleNames;
}
public Q_SLOTS:
bool insertADefaultRow()
{
loadModel();
bool retValue = insertRows(rowCount(), 1);
saveModel(m_data);
return retValue;
};
bool removeSelectedRow(int row)
{
bool retValue = removeRows(row, 1);
saveModel(m_data);
return retValue;
};
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex())
{
beginRemoveRows(parent, row, row + (count - 1));
m_data.removeAt(row);
endRemoveRows();
return true;
};
bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())
{
beginInsertRows(parent, row, row + (count - 1));
QJsonObject rowData;
rowData.insert("localPath", "");
rowData.insert("remotePath", "");
rowData.insert("direction", "DEFAULT");
rowData.insert("postSyncScript", "");
m_data.append(rowData);
endInsertRows();
return true;
};
void addSyncItem(const QString &localPath, const QString &remotePath, const QString &direction, const QString &postSyncScript)
{
QJsonObject row;
row.insert("localPath", localPath);
row.insert("remotePath", remotePath);
row.insert("direction", direction);
row.insert("postSyncScript", postSyncScript);
m_data.append(row);
qDebug() << m_data << endl;
}
void saveModel(const QJsonArray& model);
void loadModel();
};
}
#endif //KDECONNECT_SYNC_TABLE_MODEL_H
......@@ -9,6 +9,7 @@ add_executable(kdeconnect-filesync-daemon
sftp_mounter.cpp
executor.cpp
sync_operation.cpp
config.cpp
../interfaces/filesyncapp_interface.cpp
../interfaces/sync_result.cpp
../interfaces/file_hash_array.cpp
......
......@@ -60,6 +60,10 @@ namespace FileSync
// TODO this should be configurable
static const QString INDEX_PATH = "%1/.kdeconnect-sync/%2/sync_db.json";
// Sync config
// TODO this should be configurable
static const QString CONFIG_FILE_PATH = "%1/.kdeconnect-sync/%2/sync_config.json";
// Errors
static const QString NO_INSTANCE_AVAILABLE_ERROR = "No instance available, for the first time initialization please provide 'deviceId'!";
static const QString EXEC_ERROR = "Script execution failed, exit code %1";
......
......@@ -18,45 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HOOKS_CONFIG_H
#define HOOKS_CONFIG_H
#include "config.h"
#include <QStandardItemModel>
#include "kcmplugin/kdeconnectpluginkcm.h"
namespace SyncPlugin
{
class ConfigDialog
: public KdeConnectPluginKcm
{
Q_OBJECT
public:
ConfigDialog(QWidget *parent, const QVariantList &);
~ConfigDialog() override;
public Q_SLOTS:
void save() override;
void load() override;
void defaults() override;
private Q_SLOTS:
void
onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
private:
void insertRow(int i, const QString &remotePath, const QString &localPath,
const QString &postSyncScript);
void insertEmptyRow();
QStandardItemModel *m_entriesModel;
};
}
#endif
QMap<QString, FileSync::Config*>* s_instances = NULL;
/**
* Copyright 2019 Viktor Porvaznik <viktor.porvaznik@piceacode.eu>
*