Split fileitemactionplugin code into multiple files

This commit is contained in:
Martchus 2018-11-28 20:57:48 +01:00
parent 882a2a5d35
commit f901386478
11 changed files with 521 additions and 461 deletions

View File

@ -7,10 +7,18 @@ set(META_QT5_VERSION 5.8)
# add project files
set(HEADER_FILES
${META_PROJECT_NAME}.h
syncthingmenuaction.h
syncthinginfoaction.h
syncthingdiractions.h
syncthingfileitemactionstaticdata.h
syncthingfileitemaction.h
)
set(SRC_FILES
${META_PROJECT_NAME}.cpp
syncthingmenuaction.cpp
syncthinginfoaction.cpp
syncthingdiractions.cpp
syncthingfileitemactionstaticdata.cpp
syncthingfileitemaction.cpp
)
set(TS_FILES

View File

@ -0,0 +1,79 @@
#include "./syncthingdiractions.h"
#include "../model/syncthingicons.h"
#include "../connector/syncthingdir.h"
#include "../connector/utils.h"
using namespace Data;
SyncthingDirActions::SyncthingDirActions(const SyncthingDir &dir, QObject *parent)
: QObject(parent)
, m_dirId(dir.id)
{
m_infoAction.setSeparator(true);
updateStatus(dir);
}
void SyncthingDirActions::updateStatus(const std::vector<SyncthingDir> &dirs)
{
for (const SyncthingDir &dir : dirs) {
if (updateStatus(dir)) {
return;
}
}
m_statusAction.setText(tr("Status: not available anymore"));
m_statusAction.setIcon(statusIcons().disconnected);
}
bool SyncthingDirActions::updateStatus(const SyncthingDir &dir)
{
if (dir.id != m_dirId) {
return false;
}
m_infoAction.setText(tr("Directory info for %1").arg(dir.displayName()));
m_infoAction.setIcon(QIcon::fromTheme(QStringLiteral("dialog-information")));
m_statusAction.setText(tr("Status: ") + dir.statusString());
if (dir.paused && dir.status != SyncthingDirStatus::OutOfSync) {
m_statusAction.setIcon(statusIcons().pause);
} else if (dir.isUnshared()) {
m_statusAction.setIcon(statusIcons().disconnected);
} else {
switch (dir.status) {
case SyncthingDirStatus::Unknown:
m_statusAction.setIcon(statusIcons().disconnected);
break;
case SyncthingDirStatus::Idle:
m_statusAction.setIcon(statusIcons().idling);
break;
case SyncthingDirStatus::Scanning:
m_statusAction.setIcon(statusIcons().scanninig);
break;
case SyncthingDirStatus::Synchronizing:
m_statusAction.setIcon(statusIcons().sync);
break;
case SyncthingDirStatus::OutOfSync:
m_statusAction.setIcon(statusIcons().error);
break;
}
}
m_globalStatusAction.setText(tr("Global: ") + directoryStatusString(dir.globalStats));
m_localStatusAction.setText(tr("Local: ") + directoryStatusString(dir.localStats));
m_lastScanAction.setText(tr("Last scan time: ") + agoString(dir.lastScanTime));
m_lastScanAction.setIcon(QIcon::fromTheme(QStringLiteral("accept_time_event")));
m_rescanIntervalAction.setText(tr("Rescan interval: %1 seconds").arg(dir.rescanInterval));
if (!dir.pullErrorCount) {
m_errorsAction.setVisible(false);
} else {
m_errorsAction.setVisible(true);
m_errorsAction.setIcon(QIcon::fromTheme(QStringLiteral("dialog-error")));
m_errorsAction.setText(tr("%1 item(s) out-of-sync", nullptr, trQuandity(dir.pullErrorCount)).arg(dir.pullErrorCount));
}
return true;
}
QList<QAction *> &operator<<(QList<QAction *> &actions, SyncthingDirActions &dirActions)
{
return actions << &dirActions.m_infoAction << &dirActions.m_statusAction << &dirActions.m_globalStatusAction << &dirActions.m_localStatusAction
<< &dirActions.m_lastScanAction << &dirActions.m_rescanIntervalAction << &dirActions.m_errorsAction;
}

View File

@ -0,0 +1,32 @@
#ifndef SYNCTHINGDIRACTIONS_H
#define SYNCTHINGDIRACTIONS_H
#include "../connector/syncthingdir.h"
#include "./syncthinginfoaction.h"
class SyncthingDirActions : public QObject {
Q_OBJECT
friend QList<QAction *> &operator<<(QList<QAction *> &, SyncthingDirActions &);
public:
explicit SyncthingDirActions(const Data::SyncthingDir &dir, QObject *parent = nullptr);
public Q_SLOTS:
void updateStatus(const std::vector<Data::SyncthingDir> &dirs);
bool updateStatus(const Data::SyncthingDir &dir);
private:
QString m_dirId;
QAction m_infoAction;
SyncthingInfoAction m_statusAction;
SyncthingInfoAction m_globalStatusAction;
SyncthingInfoAction m_localStatusAction;
SyncthingInfoAction m_lastScanAction;
SyncthingInfoAction m_rescanIntervalAction;
SyncthingInfoAction m_errorsAction;
};
QList<QAction *> &operator<<(QList<QAction *> &actions, SyncthingDirActions &dirActions);
#endif // SYNCTHINGDIRACTIONS_H

View File

@ -1,38 +1,19 @@
#include "./syncthingfileitemaction.h"
#include "./syncthingdiractions.h"
#include "./syncthinginfoaction.h"
#include "./syncthingmenuaction.h"
#include "../model/syncthingicons.h"
#include "../connector/syncthingconfig.h"
#include "../connector/syncthingconnectionsettings.h"
#include "../connector/syncthingdir.h"
#include "../connector/utils.h"
#include <qtutilities/aboutdialog/aboutdialog.h>
#include <qtutilities/resources/resources.h>
#include <c++utilities/application/argumentparser.h>
#include <KFileItem>
#include <KPluginFactory>
#include <KPluginLoader>
#include <QAction>
#include <QDir>
#include <QEvent>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QLabel>
#include <QMenu>
#include <QMessageBox>
#include <QSettings>
#include <QWidget>
#include <functional>
#include <iostream>
#include "resources/config.h"
using namespace std;
using namespace Dialogs;
using namespace Data;
K_PLUGIN_FACTORY(SyncthingFileItemActionFactory, registerPlugin<SyncthingFileItemAction>();)
@ -56,295 +37,6 @@ SyncthingItem::SyncthingItem(const SyncthingDir *dir, const QString &path)
}
}
SyncthingMenuAction::SyncthingMenuAction(const KFileItemListProperties &properties, const QList<QAction *> &actions, QWidget *parentWidget)
: QAction(parentWidget)
, m_properties(properties)
{
if (!actions.isEmpty()) {
auto *menu = new QMenu(parentWidget);
menu->addActions(actions);
setMenu(menu);
}
updateStatus(SyncthingFileItemAction::staticData().connection().status());
}
void SyncthingMenuAction::updateStatus(SyncthingStatus status)
{
if (status != SyncthingStatus::Disconnected && status != SyncthingStatus::Reconnecting && status != SyncthingStatus::BeingDestroyed) {
setText(tr("Syncthing"));
setIcon(statusIcons().scanninig);
if (!menu()) {
const QList<QAction *> actions = SyncthingFileItemAction::createActions(m_properties, parentWidget());
if (!actions.isEmpty()) {
auto *menu = new QMenu(parentWidget());
menu->addActions(actions);
setMenu(menu);
}
}
} else {
if (status != SyncthingStatus::Reconnecting) {
SyncthingFileItemAction::staticData().connection().connect();
}
setText(tr("Syncthing - connecting"));
setIcon(statusIcons().disconnected);
if (QMenu *menu = this->menu()) {
setMenu(nullptr);
delete menu;
}
}
}
SyncthingInfoWidget::SyncthingInfoWidget(const SyncthingInfoAction *action, QWidget *parent)
: QWidget(parent)
, m_textLabel(new QLabel(parent))
, m_iconLabel(new QLabel(parent))
{
auto *const layout = new QHBoxLayout(parent);
layout->setMargin(4);
layout->setSpacing(5);
m_iconLabel->setFixedWidth(16);
m_iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
layout->addWidget(m_iconLabel);
layout->addWidget(m_textLabel);
setLayout(layout);
updateFromAction(action);
connect(action, &QAction::changed, this, &SyncthingInfoWidget::updateFromSender);
}
void SyncthingInfoWidget::updateFromSender()
{
updateFromAction(qobject_cast<const SyncthingInfoAction *>(QObject::sender()));
}
void SyncthingInfoWidget::updateFromAction(const SyncthingInfoAction *action)
{
auto text(action->text());
m_textLabel->setText(text.startsWith(QChar('&')) ? text.mid(1) : std::move(text));
m_iconLabel->setPixmap(action->icon().pixmap(16));
setVisible(action->isVisible());
}
SyncthingInfoAction::SyncthingInfoAction(QObject *parent)
: QWidgetAction(parent)
{
}
QWidget *SyncthingInfoAction::createWidget(QWidget *parent)
{
return new SyncthingInfoWidget(this, parent);
}
SyncthingDirActions::SyncthingDirActions(const SyncthingDir &dir, QObject *parent)
: QObject(parent)
, m_dirId(dir.id)
{
m_infoAction.setSeparator(true);
updateStatus(dir);
}
void SyncthingDirActions::updateStatus(const std::vector<SyncthingDir> &dirs)
{
for (const SyncthingDir &dir : dirs) {
if (updateStatus(dir)) {
return;
}
}
m_statusAction.setText(tr("Status: not available anymore"));
m_statusAction.setIcon(statusIcons().disconnected);
}
bool SyncthingDirActions::updateStatus(const SyncthingDir &dir)
{
if (dir.id != m_dirId) {
return false;
}
m_infoAction.setText(tr("Directory info for %1").arg(dir.displayName()));
m_infoAction.setIcon(QIcon::fromTheme(QStringLiteral("dialog-information")));
m_statusAction.setText(tr("Status: ") + dir.statusString());
if (dir.paused && dir.status != SyncthingDirStatus::OutOfSync) {
m_statusAction.setIcon(statusIcons().pause);
} else if (dir.isUnshared()) {
m_statusAction.setIcon(statusIcons().disconnected);
} else {
switch (dir.status) {
case SyncthingDirStatus::Unknown:
m_statusAction.setIcon(statusIcons().disconnected);
break;
case SyncthingDirStatus::Idle:
m_statusAction.setIcon(statusIcons().idling);
break;
case SyncthingDirStatus::Scanning:
m_statusAction.setIcon(statusIcons().scanninig);
break;
case SyncthingDirStatus::Synchronizing:
m_statusAction.setIcon(statusIcons().sync);
break;
case SyncthingDirStatus::OutOfSync:
m_statusAction.setIcon(statusIcons().error);
break;
}
}
m_globalStatusAction.setText(tr("Global: ") + directoryStatusString(dir.globalStats));
m_localStatusAction.setText(tr("Local: ") + directoryStatusString(dir.localStats));
m_lastScanAction.setText(tr("Last scan time: ") + agoString(dir.lastScanTime));
m_lastScanAction.setIcon(QIcon::fromTheme(QStringLiteral("accept_time_event")));
m_rescanIntervalAction.setText(tr("Rescan interval: %1 seconds").arg(dir.rescanInterval));
if (!dir.pullErrorCount) {
m_errorsAction.setVisible(false);
} else {
m_errorsAction.setVisible(true);
m_errorsAction.setIcon(QIcon::fromTheme(QStringLiteral("dialog-error")));
m_errorsAction.setText(tr("%1 item(s) out-of-sync", nullptr, trQuandity(dir.pullErrorCount)).arg(dir.pullErrorCount));
}
return true;
}
QList<QAction *> &operator<<(QList<QAction *> &actions, SyncthingDirActions &dirActions)
{
return actions << &dirActions.m_infoAction << &dirActions.m_statusAction << &dirActions.m_globalStatusAction << &dirActions.m_localStatusAction
<< &dirActions.m_lastScanAction << &dirActions.m_rescanIntervalAction << &dirActions.m_errorsAction;
}
SyncthingFileItemActionStaticData::SyncthingFileItemActionStaticData()
: m_initialized(false)
{
}
SyncthingFileItemActionStaticData::~SyncthingFileItemActionStaticData()
{
}
void SyncthingFileItemActionStaticData::initialize()
{
if (m_initialized) {
return;
}
LOAD_QT_TRANSLATIONS;
// load settings
const QSettings settingsFile(QSettings::IniFormat, QSettings::UserScope, QStringLiteral(PROJECT_NAME));
// determine path of Syncthing config file
m_configFilePath = [&] {
const QByteArray configPathFromEnv(qgetenv("KIO_SYNCTHING_CONFIG_PATH"));
if (!configPathFromEnv.isEmpty()) {
return QString::fromLocal8Bit(configPathFromEnv);
}
const QString configPathFromSettings = settingsFile.value(QStringLiteral("syncthingConfigPath")).toString();
if (!configPathFromSettings.isEmpty()) {
return configPathFromSettings;
}
return SyncthingConfig::locateConfigFile();
}();
applySyncthingConfiguration(m_configFilePath);
// prevent unnecessary API calls (for the purpose of the context menu)
m_connection.disablePolling();
// connect Signals & Slots for logging
connect(&m_connection, &SyncthingConnection::error, this, &SyncthingFileItemActionStaticData::logConnectionError);
if (qEnvironmentVariableIsSet("KIO_SYNCTHING_LOG_STATUS")) {
connect(&m_connection, &SyncthingConnection::statusChanged, this, &SyncthingFileItemActionStaticData::logConnectionStatus);
}
m_initialized = true;
}
void SyncthingFileItemActionStaticData::logConnectionStatus()
{
cerr << "Syncthing connection status changed to: " << m_connection.statusText().toLocal8Bit().data() << endl;
}
void SyncthingFileItemActionStaticData::logConnectionError(const QString &errorMessage, SyncthingErrorCategory errorCategory)
{
switch (errorCategory) {
case SyncthingErrorCategory::Parsing:
case SyncthingErrorCategory::SpecificRequest:
QMessageBox::critical(nullptr, tr("Syncthing connection error"), errorMessage);
break;
default:
cerr << "Syncthing connection error: " << errorMessage.toLocal8Bit().data() << endl;
}
}
void SyncthingFileItemActionStaticData::rescanDir(const QString &dirId, const QString &relpath)
{
m_connection.rescan(dirId, relpath);
}
void SyncthingFileItemActionStaticData::showAboutDialog()
{
auto *aboutDialog = new AboutDialog(nullptr, QStringLiteral(APP_NAME), QStringLiteral(APP_AUTHOR "\nSyncthing icons from Syncthing project"),
QStringLiteral(APP_VERSION), ApplicationUtilities::dependencyVersions2, QStringLiteral(APP_URL), QStringLiteral(APP_DESCRIPTION),
QImage(statusIcons().scanninig.pixmap(128).toImage()));
aboutDialog->setWindowTitle(tr("About") + QStringLiteral(" - " APP_NAME));
aboutDialog->setWindowIcon(QIcon::fromTheme(QStringLiteral("syncthingtray")));
aboutDialog->setAttribute(Qt::WA_DeleteOnClose);
aboutDialog->show();
}
void SyncthingFileItemActionStaticData::selectSyncthingConfig()
{
const auto configFilePath = QFileDialog::getOpenFileName(nullptr, tr("Select Syncthing config file") + QStringLiteral(" - " APP_NAME));
if (!configFilePath.isEmpty() && applySyncthingConfiguration(configFilePath)) {
QSettings(QSettings::IniFormat, QSettings::UserScope, QStringLiteral(PROJECT_NAME))
.setValue(QStringLiteral("syncthingConfigPath"), m_configFilePath = configFilePath);
}
}
bool SyncthingFileItemActionStaticData::applySyncthingConfiguration(const QString &syncthingConfigFilePath)
{
clearCurrentError();
// check for empty path
if (syncthingConfigFilePath.isEmpty()) {
setCurrentError(tr("Syncthing config file can not be automatically located"));
return false;
}
// load Syncthing config
SyncthingConfig config;
if (!config.restore(syncthingConfigFilePath)) {
auto errorMessage = tr("Unable to load Syncthing config from \"%1\"").arg(syncthingConfigFilePath);
if (!m_configFilePath.isEmpty() && m_configFilePath != syncthingConfigFilePath) {
errorMessage += QChar('\n');
errorMessage += tr("(still using config from \"%1\")").arg(m_configFilePath);
}
setCurrentError(errorMessage);
return false;
}
cerr << "Syncthing config loaded from \"" << syncthingConfigFilePath.toLocal8Bit().data() << "\"" << endl;
// make connection settings
SyncthingConnectionSettings settings;
settings.syncthingUrl = config.syncthingUrl();
settings.apiKey.append(config.guiApiKey);
// establish connection
bool ok;
int reconnectInterval = qEnvironmentVariableIntValue("KIO_SYNCTHING_RECONNECT_INTERVAL", &ok);
if (!ok || reconnectInterval < 0) {
reconnectInterval = 10000;
}
m_connection.setAutoReconnectInterval(reconnectInterval);
m_connection.reconnect(settings);
return true;
}
void SyncthingFileItemActionStaticData::setCurrentError(const QString &currentError)
{
if (m_currentError == currentError) {
return;
}
const bool hadError = hasError();
m_currentError = currentError;
if (hadError != hasError()) {
emit hasErrorChanged(hasError());
}
emit currentErrorChanged(m_currentError);
}
SyncthingFileItemActionStaticData SyncthingFileItemAction::s_data;
SyncthingFileItemAction::SyncthingFileItemAction(QObject *parent, const QVariantList &)

View File

@ -1,158 +1,12 @@
#ifndef SYNCTHINGFILEITEMACTION_H
#define SYNCTHINGFILEITEMACTION_H
#include "../connector/syncthingconnection.h"
#include "./syncthingfileitemactionstaticdata.h"
#include <KAbstractFileItemActionPlugin>
#include <KFileItemListProperties>
#include <QAction>
#include <QWidget>
#include <QWidgetAction>
QT_FORWARD_DECLARE_CLASS(QLabel)
class KFileItemListProperties;
class SyncthingMenuAction : public QAction {
Q_OBJECT
public:
explicit SyncthingMenuAction(const KFileItemListProperties &properties = KFileItemListProperties(),
const QList<QAction *> &actions = QList<QAction *>(), QWidget *parentWidget = nullptr);
public Q_SLOTS:
void updateStatus(Data::SyncthingStatus status);
private:
KFileItemListProperties m_properties;
};
class SyncthingInfoAction;
class SyncthingInfoWidget : public QWidget {
Q_OBJECT
public:
explicit SyncthingInfoWidget(const SyncthingInfoAction *action, QWidget *parent = nullptr);
private Q_SLOTS:
void updateFromSender();
void updateFromAction(const SyncthingInfoAction *action);
private:
QLabel *const m_textLabel;
QLabel *const m_iconLabel;
};
class SyncthingInfoAction : public QWidgetAction {
Q_OBJECT
public:
explicit SyncthingInfoAction(QObject *parent = nullptr);
protected:
QWidget *createWidget(QWidget *parent) override;
};
class SyncthingDirActions : public QObject {
Q_OBJECT
friend QList<QAction *> &operator<<(QList<QAction *> &, SyncthingDirActions &);
public:
explicit SyncthingDirActions(const Data::SyncthingDir &dir, QObject *parent = nullptr);
public Q_SLOTS:
void updateStatus(const std::vector<Data::SyncthingDir> &dirs);
bool updateStatus(const Data::SyncthingDir &dir);
private:
QString m_dirId;
QAction m_infoAction;
SyncthingInfoAction m_statusAction;
SyncthingInfoAction m_globalStatusAction;
SyncthingInfoAction m_localStatusAction;
SyncthingInfoAction m_lastScanAction;
SyncthingInfoAction m_rescanIntervalAction;
SyncthingInfoAction m_errorsAction;
};
QList<QAction *> &operator<<(QList<QAction *> &actions, SyncthingDirActions &dirActions);
class SyncthingFileItemActionStaticData : public QObject {
Q_OBJECT
Q_PROPERTY(QString configPath READ configPath)
Q_PROPERTY(QString currentError READ currentError WRITE setCurrentError NOTIFY currentErrorChanged RESET clearCurrentError)
Q_PROPERTY(bool hasError READ hasError NOTIFY hasErrorChanged)
Q_PROPERTY(bool initialized READ isInitialized)
public:
explicit SyncthingFileItemActionStaticData();
~SyncthingFileItemActionStaticData();
Data::SyncthingConnection &connection();
const Data::SyncthingConnection &connection() const;
const QString &configPath() const;
const QString &currentError() const;
bool hasError() const;
bool isInitialized() const;
public Q_SLOTS:
void initialize();
bool applySyncthingConfiguration(const QString &syncthingConfigFilePath);
void logConnectionStatus();
void logConnectionError(const QString &errorMessage, Data::SyncthingErrorCategory errorCategory);
void rescanDir(const QString &dirId, const QString &relpath = QString());
static void showAboutDialog();
void selectSyncthingConfig();
void setCurrentError(const QString &currentError);
void clearCurrentError();
Q_SIGNALS:
void currentErrorChanged(const QString &error);
void hasErrorChanged(bool hasError);
private:
Data::SyncthingConnection m_connection;
QString m_configFilePath;
QString m_currentError;
bool m_initialized;
};
inline Data::SyncthingConnection &SyncthingFileItemActionStaticData::connection()
{
return m_connection;
}
inline const Data::SyncthingConnection &SyncthingFileItemActionStaticData::connection() const
{
return m_connection;
}
inline const QString &SyncthingFileItemActionStaticData::configPath() const
{
return m_configFilePath;
}
inline const QString &SyncthingFileItemActionStaticData::currentError() const
{
return m_currentError;
}
inline bool SyncthingFileItemActionStaticData::hasError() const
{
return !currentError().isEmpty();
}
inline bool SyncthingFileItemActionStaticData::isInitialized() const
{
return m_initialized;
}
inline void SyncthingFileItemActionStaticData::clearCurrentError()
{
m_currentError.clear();
}
class SyncthingFileItemAction : public KAbstractFileItemActionPlugin {
Q_OBJECT

View File

@ -0,0 +1,160 @@
#include "./syncthingfileitemactionstaticdata.h"
#include "../model/syncthingicons.h"
#include "../connector/syncthingconfig.h"
#include "../connector/syncthingconnection.h"
#include "../connector/syncthingconnectionsettings.h"
#include <c++utilities/application/argumentparser.h>
#include <qtutilities/aboutdialog/aboutdialog.h>
#include <qtutilities/resources/resources.h>
#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
#include <iostream>
#include "resources/config.h"
using namespace std;
using namespace Dialogs;
using namespace Data;
SyncthingFileItemActionStaticData::SyncthingFileItemActionStaticData()
: m_initialized(false)
{
}
void SyncthingFileItemActionStaticData::initialize()
{
if (m_initialized) {
return;
}
LOAD_QT_TRANSLATIONS;
// load settings
const QSettings settingsFile(QSettings::IniFormat, QSettings::UserScope, QStringLiteral(PROJECT_NAME));
// determine path of Syncthing config file
m_configFilePath = [&] {
const QByteArray configPathFromEnv(qgetenv("KIO_SYNCTHING_CONFIG_PATH"));
if (!configPathFromEnv.isEmpty()) {
return QString::fromLocal8Bit(configPathFromEnv);
}
const QString configPathFromSettings = settingsFile.value(QStringLiteral("syncthingConfigPath")).toString();
if (!configPathFromSettings.isEmpty()) {
return configPathFromSettings;
}
return SyncthingConfig::locateConfigFile();
}();
applySyncthingConfiguration(m_configFilePath);
// prevent unnecessary API calls (for the purpose of the context menu)
m_connection.disablePolling();
// connect Signals & Slots for logging
connect(&m_connection, &SyncthingConnection::error, this, &SyncthingFileItemActionStaticData::logConnectionError);
if (qEnvironmentVariableIsSet("KIO_SYNCTHING_LOG_STATUS")) {
connect(&m_connection, &SyncthingConnection::statusChanged, this, &SyncthingFileItemActionStaticData::logConnectionStatus);
}
m_initialized = true;
}
void SyncthingFileItemActionStaticData::logConnectionStatus()
{
cerr << "Syncthing connection status changed to: " << m_connection.statusText().toLocal8Bit().data() << endl;
}
void SyncthingFileItemActionStaticData::logConnectionError(const QString &errorMessage, SyncthingErrorCategory errorCategory)
{
switch (errorCategory) {
case SyncthingErrorCategory::Parsing:
case SyncthingErrorCategory::SpecificRequest:
QMessageBox::critical(nullptr, tr("Syncthing connection error"), errorMessage);
break;
default:
cerr << "Syncthing connection error: " << errorMessage.toLocal8Bit().data() << endl;
}
}
void SyncthingFileItemActionStaticData::rescanDir(const QString &dirId, const QString &relpath)
{
m_connection.rescan(dirId, relpath);
}
void SyncthingFileItemActionStaticData::showAboutDialog()
{
auto *aboutDialog = new AboutDialog(nullptr, QStringLiteral(APP_NAME), QStringLiteral(APP_AUTHOR "\nSyncthing icons from Syncthing project"),
QStringLiteral(APP_VERSION), ApplicationUtilities::dependencyVersions2, QStringLiteral(APP_URL), QStringLiteral(APP_DESCRIPTION),
QImage(statusIcons().scanninig.pixmap(128).toImage()));
aboutDialog->setWindowTitle(tr("About") + QStringLiteral(" - " APP_NAME));
aboutDialog->setWindowIcon(QIcon::fromTheme(QStringLiteral("syncthingtray")));
aboutDialog->setAttribute(Qt::WA_DeleteOnClose);
aboutDialog->show();
}
void SyncthingFileItemActionStaticData::selectSyncthingConfig()
{
const auto configFilePath = QFileDialog::getOpenFileName(nullptr, tr("Select Syncthing config file") + QStringLiteral(" - " APP_NAME));
if (!configFilePath.isEmpty() && applySyncthingConfiguration(configFilePath)) {
QSettings(QSettings::IniFormat, QSettings::UserScope, QStringLiteral(PROJECT_NAME))
.setValue(QStringLiteral("syncthingConfigPath"), m_configFilePath = configFilePath);
}
}
bool SyncthingFileItemActionStaticData::applySyncthingConfiguration(const QString &syncthingConfigFilePath)
{
clearCurrentError();
// check for empty path
if (syncthingConfigFilePath.isEmpty()) {
setCurrentError(tr("Syncthing config file can not be automatically located"));
return false;
}
// load Syncthing config
SyncthingConfig config;
if (!config.restore(syncthingConfigFilePath)) {
auto errorMessage = tr("Unable to load Syncthing config from \"%1\"").arg(syncthingConfigFilePath);
if (!m_configFilePath.isEmpty() && m_configFilePath != syncthingConfigFilePath) {
errorMessage += QChar('\n');
errorMessage += tr("(still using config from \"%1\")").arg(m_configFilePath);
}
setCurrentError(errorMessage);
return false;
}
cerr << "Syncthing config loaded from \"" << syncthingConfigFilePath.toLocal8Bit().data() << "\"" << endl;
// make connection settings
SyncthingConnectionSettings settings;
settings.syncthingUrl = config.syncthingUrl();
settings.apiKey.append(config.guiApiKey);
// establish connection
bool ok;
int reconnectInterval = qEnvironmentVariableIntValue("KIO_SYNCTHING_RECONNECT_INTERVAL", &ok);
if (!ok || reconnectInterval < 0) {
reconnectInterval = 10000;
}
m_connection.setAutoReconnectInterval(reconnectInterval);
m_connection.reconnect(settings);
return true;
}
void SyncthingFileItemActionStaticData::setCurrentError(const QString &currentError)
{
if (m_currentError == currentError) {
return;
}
const bool hadError = hasError();
m_currentError = currentError;
if (hadError != hasError()) {
emit hasErrorChanged(hasError());
}
emit currentErrorChanged(m_currentError);
}

View File

@ -0,0 +1,79 @@
#ifndef SYNCTHINGFILEITEMACTIONSTATICDATA_H
#define SYNCTHINGFILEITEMACTIONSTATICDATA_H
#include "../connector/syncthingconnection.h"
class SyncthingFileItemActionStaticData : public QObject {
Q_OBJECT
Q_PROPERTY(QString configPath READ configPath)
Q_PROPERTY(QString currentError READ currentError WRITE setCurrentError NOTIFY currentErrorChanged RESET clearCurrentError)
Q_PROPERTY(bool hasError READ hasError NOTIFY hasErrorChanged)
Q_PROPERTY(bool initialized READ isInitialized)
public:
explicit SyncthingFileItemActionStaticData();
Data::SyncthingConnection &connection();
const Data::SyncthingConnection &connection() const;
const QString &configPath() const;
const QString &currentError() const;
bool hasError() const;
bool isInitialized() const;
public Q_SLOTS:
void initialize();
bool applySyncthingConfiguration(const QString &syncthingConfigFilePath);
void logConnectionStatus();
void logConnectionError(const QString &errorMessage, Data::SyncthingErrorCategory errorCategory);
void rescanDir(const QString &dirId, const QString &relpath = QString());
static void showAboutDialog();
void selectSyncthingConfig();
void setCurrentError(const QString &currentError);
void clearCurrentError();
Q_SIGNALS:
void currentErrorChanged(const QString &error);
void hasErrorChanged(bool hasError);
private:
Data::SyncthingConnection m_connection;
QString m_configFilePath;
QString m_currentError;
bool m_initialized;
};
inline Data::SyncthingConnection &SyncthingFileItemActionStaticData::connection()
{
return m_connection;
}
inline const Data::SyncthingConnection &SyncthingFileItemActionStaticData::connection() const
{
return m_connection;
}
inline const QString &SyncthingFileItemActionStaticData::configPath() const
{
return m_configFilePath;
}
inline const QString &SyncthingFileItemActionStaticData::currentError() const
{
return m_currentError;
}
inline bool SyncthingFileItemActionStaticData::hasError() const
{
return !currentError().isEmpty();
}
inline bool SyncthingFileItemActionStaticData::isInitialized() const
{
return m_initialized;
}
inline void SyncthingFileItemActionStaticData::clearCurrentError()
{
m_currentError.clear();
}
#endif // SYNCTHINGFILEITEMACTIONSTATICDATA_H

View File

@ -0,0 +1,45 @@
#include "./syncthinginfoaction.h"
#include <QAction>
#include <QHBoxLayout>
#include <QLabel>
SyncthingInfoWidget::SyncthingInfoWidget(const SyncthingInfoAction *action, QWidget *parent)
: QWidget(parent)
, m_textLabel(new QLabel(parent))
, m_iconLabel(new QLabel(parent))
{
auto *const layout = new QHBoxLayout(parent);
layout->setMargin(4);
layout->setSpacing(5);
m_iconLabel->setFixedWidth(16);
m_iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
layout->addWidget(m_iconLabel);
layout->addWidget(m_textLabel);
setLayout(layout);
updateFromAction(action);
connect(action, &QAction::changed, this, &SyncthingInfoWidget::updateFromSender);
}
void SyncthingInfoWidget::updateFromSender()
{
updateFromAction(qobject_cast<const SyncthingInfoAction *>(QObject::sender()));
}
void SyncthingInfoWidget::updateFromAction(const SyncthingInfoAction *action)
{
auto text(action->text());
m_textLabel->setText(text.startsWith(QChar('&')) ? text.mid(1) : std::move(text));
m_iconLabel->setPixmap(action->icon().pixmap(16));
setVisible(action->isVisible());
}
SyncthingInfoAction::SyncthingInfoAction(QObject *parent)
: QWidgetAction(parent)
{
}
QWidget *SyncthingInfoAction::createWidget(QWidget *parent)
{
return new SyncthingInfoWidget(this, parent);
}

View File

@ -0,0 +1,36 @@
#ifndef SYNCTHINGINFOACTION_H
#define SYNCTHINGINFOACTION_H
#include <QWidget>
#include <QWidgetAction>
QT_FORWARD_DECLARE_CLASS(QLabel)
class SyncthingInfoAction;
class SyncthingInfoWidget : public QWidget {
Q_OBJECT
public:
explicit SyncthingInfoWidget(const SyncthingInfoAction *action, QWidget *parent = nullptr);
private Q_SLOTS:
void updateFromSender();
void updateFromAction(const SyncthingInfoAction *action);
private:
QLabel *const m_textLabel;
QLabel *const m_iconLabel;
};
class SyncthingInfoAction : public QWidgetAction {
Q_OBJECT
public:
explicit SyncthingInfoAction(QObject *parent = nullptr);
protected:
QWidget *createWidget(QWidget *parent) override;
};
#endif // SYNCTHINGINFOACTION_H

View File

@ -0,0 +1,49 @@
#include "./syncthingmenuaction.h"
#include "./syncthingfileitemaction.h"
#include "../model/syncthingicons.h"
#include "../connector/syncthingconnection.h"
#include <QAction>
#include <QMenu>
using namespace Data;
SyncthingMenuAction::SyncthingMenuAction(const KFileItemListProperties &properties, const QList<QAction *> &actions, QWidget *parentWidget)
: QAction(parentWidget)
, m_properties(properties)
{
if (!actions.isEmpty()) {
auto *menu = new QMenu(parentWidget);
menu->addActions(actions);
setMenu(menu);
}
updateStatus(SyncthingFileItemAction::staticData().connection().status());
}
void SyncthingMenuAction::updateStatus(SyncthingStatus status)
{
if (status != SyncthingStatus::Disconnected && status != SyncthingStatus::Reconnecting && status != SyncthingStatus::BeingDestroyed) {
setText(tr("Syncthing"));
setIcon(statusIcons().scanninig);
if (!menu()) {
const QList<QAction *> actions = SyncthingFileItemAction::createActions(m_properties, parentWidget());
if (!actions.isEmpty()) {
auto *menu = new QMenu(parentWidget());
menu->addActions(actions);
setMenu(menu);
}
}
} else {
if (status != SyncthingStatus::Reconnecting) {
SyncthingFileItemAction::staticData().connection().connect();
}
setText(tr("Syncthing - connecting"));
setIcon(statusIcons().disconnected);
if (QMenu *menu = this->menu()) {
setMenu(nullptr);
delete menu;
}
}
}

View File

@ -0,0 +1,26 @@
#ifndef SYNCTHINGMENUACTION_H
#define SYNCTHINGMENUACTION_H
#include <KFileItemListProperties>
#include <QAction>
namespace Data {
enum class SyncthingStatus;
}
class SyncthingMenuAction : public QAction {
Q_OBJECT
public:
explicit SyncthingMenuAction(const KFileItemListProperties &properties = KFileItemListProperties(),
const QList<QAction *> &actions = QList<QAction *>(), QWidget *parentWidget = nullptr);
public Q_SLOTS:
void updateStatus(Data::SyncthingStatus status);
private:
KFileItemListProperties m_properties;
};
#endif // SYNCTHINGMENUACTION_H