Make Dolphin integration configurable

* Allow to select Syncthing config file manually
* Show error if config file can not be located
This commit is contained in:
Martchus 2018-11-27 17:59:17 +01:00
parent ba4012fb36
commit 882a2a5d35
2 changed files with 309 additions and 123 deletions

View File

@ -18,10 +18,12 @@
#include <QAction>
#include <QDir>
#include <QEvent>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QLabel>
#include <QMenu>
#include <QMessageBox>
#include <QSettings>
#include <QWidget>
#include <functional>
@ -63,7 +65,7 @@ SyncthingMenuAction::SyncthingMenuAction(const KFileItemListProperties &properti
menu->addActions(actions);
setMenu(menu);
}
updateStatus(SyncthingFileItemAction::connection().status());
updateStatus(SyncthingFileItemAction::staticData().connection().status());
}
void SyncthingMenuAction::updateStatus(SyncthingStatus status)
@ -81,7 +83,7 @@ void SyncthingMenuAction::updateStatus(SyncthingStatus status)
}
} else {
if (status != SyncthingStatus::Reconnecting) {
SyncthingFileItemAction::connection().connect();
SyncthingFileItemAction::staticData().connection().connect();
}
setText(tr("Syncthing - connecting"));
setIcon(statusIcons().disconnected);
@ -92,6 +94,36 @@ void SyncthingMenuAction::updateStatus(SyncthingStatus status)
}
}
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)
{
@ -99,19 +131,7 @@ SyncthingInfoAction::SyncthingInfoAction(QObject *parent)
QWidget *SyncthingInfoAction::createWidget(QWidget *parent)
{
auto *container = new QWidget(parent);
auto *layout = new QHBoxLayout(parent);
layout->setMargin(4);
layout->setSpacing(5);
auto *iconLabel = new QLabel(parent);
iconLabel->setPixmap(icon().pixmap(16));
iconLabel->setFixedWidth(16);
iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
layout->addWidget(iconLabel);
auto *textLabel = new QLabel(text(), parent);
layout->addWidget(textLabel);
container->setLayout(layout);
return container;
return new SyncthingInfoWidget(this, parent);
}
SyncthingDirActions::SyncthingDirActions(const SyncthingDir &dir, QObject *parent)
@ -185,85 +205,58 @@ QList<QAction *> &operator<<(QList<QAction *> &actions, SyncthingDirActions &dir
<< &dirActions.m_lastScanAction << &dirActions.m_rescanIntervalAction << &dirActions.m_errorsAction;
}
SyncthingConnection SyncthingFileItemAction::s_connection;
SyncthingFileItemAction::SyncthingFileItemAction(QObject *parent, const QVariantList &)
: KAbstractFileItemActionPlugin(parent)
SyncthingFileItemActionStaticData::SyncthingFileItemActionStaticData()
: m_initialized(false)
{
// skip initialization if not the first instantiation
if (!s_connection.apiKey().isEmpty()) {
}
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
const QByteArray configPathFromEnv(qgetenv("KIO_SYNCTHING_CONFIG_PATH"));
const QString configPath = !configPathFromEnv.isEmpty() ? QString::fromLocal8Bit(configPathFromEnv) : SyncthingConfig::locateConfigFile();
if (configPath.isEmpty()) {
cerr << "Unable to determine location of Syncthing config. Set KIO_SYNCTHING_CONFIG_PATH to specify location." << endl;
return;
}
// load Syncthing config
SyncthingConfig config;
if (!config.restore(configPath)) {
cerr << "Unable to load Syncthing config from \"" << configPath.toLocal8Bit().data() << "\"" << endl;
if (configPathFromEnv.isEmpty()) {
cerr << "Note: Set KIO_SYNCTHING_CONFIG_PATH to specify config file explicitely." << endl;
m_configFilePath = [&] {
const QByteArray configPathFromEnv(qgetenv("KIO_SYNCTHING_CONFIG_PATH"));
if (!configPathFromEnv.isEmpty()) {
return QString::fromLocal8Bit(configPathFromEnv);
}
return;
}
cerr << "Syncthing config loaded from \"" << configPath.toLocal8Bit().data() << "\"" << endl;
SyncthingConnectionSettings settings;
settings.syncthingUrl = config.syncthingUrl();
settings.apiKey.append(config.guiApiKey);
const QString configPathFromSettings = settingsFile.value(QStringLiteral("syncthingConfigPath")).toString();
if (!configPathFromSettings.isEmpty()) {
return configPathFromSettings;
}
return SyncthingConfig::locateConfigFile();
}();
applySyncthingConfiguration(m_configFilePath);
// establish connection
bool ok;
int reconnectInterval = qEnvironmentVariableIntValue("KIO_SYNCTHING_RECONNECT_INTERVAL", &ok);
if (!ok || reconnectInterval < 0) {
reconnectInterval = 10000;
}
s_connection.setAutoReconnectInterval(reconnectInterval);
s_connection.reconnect(settings);
connect(&s_connection, &SyncthingConnection::error, &SyncthingFileItemAction::logConnectionError);
// 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(&s_connection, &SyncthingConnection::statusChanged, &SyncthingFileItemAction::logConnectionStatus);
}
}
QList<QAction *> SyncthingFileItemAction::actions(const KFileItemListProperties &fileItemInfo, QWidget *parentWidget)
{
// handle case when not connected yet
if (!s_connection.isConnected()) {
s_connection.connect();
auto *menuAction = new SyncthingMenuAction(fileItemInfo, QList<QAction *>(), parentWidget);
connect(&s_connection, &SyncthingConnection::statusChanged, menuAction, &SyncthingMenuAction::updateStatus);
return QList<QAction *>() << menuAction;
connect(&m_connection, &SyncthingConnection::statusChanged, this, &SyncthingFileItemActionStaticData::logConnectionStatus);
}
const QList<QAction *> actions = createActions(fileItemInfo, parentWidget);
// don't show anything if no relevant actions could be determined
if (actions.isEmpty()) {
return actions;
}
return QList<QAction *>() << new SyncthingMenuAction(fileItemInfo, actions, parentWidget);
m_initialized = true;
}
SyncthingConnection &SyncthingFileItemAction::connection()
void SyncthingFileItemActionStaticData::logConnectionStatus()
{
return s_connection;
cerr << "Syncthing connection status changed to: " << m_connection.statusText().toLocal8Bit().data() << endl;
}
void SyncthingFileItemAction::logConnectionStatus()
{
cerr << "Syncthing connection status changed to: " << s_connection.statusText().toLocal8Bit().data() << endl;
}
void SyncthingFileItemAction::logConnectionError(const QString &errorMessage, SyncthingErrorCategory errorCategory)
void SyncthingFileItemActionStaticData::logConnectionError(const QString &errorMessage, SyncthingErrorCategory errorCategory)
{
switch (errorCategory) {
case SyncthingErrorCategory::Parsing:
@ -275,12 +268,12 @@ void SyncthingFileItemAction::logConnectionError(const QString &errorMessage, Sy
}
}
void SyncthingFileItemAction::rescanDir(const QString &dirId, const QString &relpath)
void SyncthingFileItemActionStaticData::rescanDir(const QString &dirId, const QString &relpath)
{
s_connection.rescan(dirId, relpath);
m_connection.rescan(dirId, relpath);
}
void SyncthingFileItemAction::showAboutDialog()
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),
@ -291,15 +284,100 @@ void SyncthingFileItemAction::showAboutDialog()
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 &)
: KAbstractFileItemActionPlugin(parent)
{
s_data.initialize();
}
QList<QAction *> SyncthingFileItemAction::actions(const KFileItemListProperties &fileItemInfo, QWidget *parentWidget)
{
// handle case when not connected yet
if (!s_data.connection().isConnected()) {
s_data.connection().connect();
auto *menuAction = new SyncthingMenuAction(fileItemInfo, QList<QAction *>(), parentWidget);
connect(&s_data.connection(), &SyncthingConnection::statusChanged, menuAction, &SyncthingMenuAction::updateStatus);
return QList<QAction *>() << menuAction;
}
const QList<QAction *> actions = createActions(fileItemInfo, parentWidget);
// don't show anything if no relevant actions could be determined
if (actions.isEmpty()) {
return actions;
}
return QList<QAction *>({ new SyncthingMenuAction(fileItemInfo, actions, parentWidget) });
}
QList<QAction *> SyncthingFileItemAction::createActions(const KFileItemListProperties &fileItemInfo, QWidget *parentWidget)
{
QList<QAction *> actions;
// check whether any directories are known
const auto &dirs = s_connection.dirInfo();
if (dirs.empty()) {
return actions;
}
auto &data = s_data;
auto &connection = data.connection();
const auto &dirs = connection.dirInfo();
// get all paths
QStringList paths;
@ -307,7 +385,7 @@ QList<QAction *> SyncthingFileItemAction::createActions(const KFileItemListPrope
for (const KFileItem &item : fileItemInfo.items()) {
if (!item.isLocalFile()) {
// don't show any actions when remote files are selected
return QList<QAction *>();
return actions;
}
paths << item.localPath();
}
@ -316,7 +394,7 @@ QList<QAction *> SyncthingFileItemAction::createActions(const KFileItemListPrope
QList<const SyncthingDir *> detectedDirs;
QList<const SyncthingDir *> containingDirs;
QList<SyncthingItem> detectedItems;
const SyncthingDir *lastDir;
const SyncthingDir *lastDir = nullptr;
for (const SyncthingDir &dir : dirs) {
QStringRef dirPath(dir.pathWithoutTrailingSlash());
for (const QString &path : paths) {
@ -336,14 +414,15 @@ QList<QAction *> SyncthingFileItemAction::createActions(const KFileItemListPrope
}
// add actions for the selected items itself
actions.reserve(32);
if (!detectedItems.isEmpty()) {
actions << new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")),
detectedItems.size() == 1 ? tr("Rescan %1 (in %2)").arg(detectedItems.front().name, detectedItems.front().dir->displayName())
: tr("Rescan selected items"),
parentWidget);
if (s_connection.isConnected()) {
if (connection.isConnected()) {
for (const SyncthingItem &item : detectedItems) {
connect(actions.back(), &QAction::triggered, bind(&SyncthingFileItemAction::rescanDir, item.dir->id, item.path));
connect(actions.back(), &QAction::triggered, bind(&SyncthingFileItemActionStaticData::rescanDir, &data, item.dir->id, item.path));
}
} else {
actions.back()->setEnabled(false);
@ -355,9 +434,9 @@ QList<QAction *> SyncthingFileItemAction::createActions(const KFileItemListPrope
// rescan item
actions << new QAction(QIcon::fromTheme(QStringLiteral("folder-sync")),
detectedDirs.size() == 1 ? tr("Rescan %1").arg(detectedDirs.front()->displayName()) : tr("Rescan selected directories"), parentWidget);
if (s_connection.isConnected()) {
if (connection.isConnected()) {
for (const SyncthingDir *dir : detectedDirs) {
connect(actions.back(), &QAction::triggered, bind(&SyncthingFileItemAction::rescanDir, dir->id, QString()));
connect(actions.back(), &QAction::triggered, bind(&SyncthingFileItemActionStaticData::rescanDir, &data, dir->id, QString()));
containingDirs.removeAll(dir);
}
} else {
@ -383,9 +462,9 @@ QList<QAction *> SyncthingFileItemAction::createActions(const KFileItemListPrope
actions << new QAction(QIcon::fromTheme(QStringLiteral("media-playback-pause")),
detectedDirs.size() == 1 ? tr("Pause %1").arg(detectedDirs.front()->displayName()) : tr("Pause selected directories"), parentWidget);
}
if (s_connection.isConnected()) {
if (connection.isConnected()) {
connect(actions.back(), &QAction::triggered,
bind(isPaused ? &SyncthingConnection::resumeDirectories : &SyncthingConnection::pauseDirectories, &s_connection, ids));
bind(isPaused ? &SyncthingConnection::resumeDirectories : &SyncthingConnection::pauseDirectories, &connection, ids));
} else {
actions.back()->setEnabled(false);
}
@ -397,9 +476,9 @@ QList<QAction *> SyncthingFileItemAction::createActions(const KFileItemListPrope
actions << new QAction(QIcon::fromTheme(QStringLiteral("folder-sync")),
containingDirs.size() == 1 ? tr("Rescan %1").arg(containingDirs.front()->displayName()) : tr("Rescan containing directories"),
parentWidget);
if (s_connection.isConnected()) {
if (connection.isConnected()) {
for (const SyncthingDir *dir : containingDirs) {
connect(actions.back(), &QAction::triggered, bind(&SyncthingFileItemAction::rescanDir, dir->id, QString()));
connect(actions.back(), &QAction::triggered, bind(&SyncthingFileItemActionStaticData::rescanDir, &data, dir->id, QString()));
}
} else {
actions.back()->setEnabled(false);
@ -425,35 +504,50 @@ QList<QAction *> SyncthingFileItemAction::createActions(const KFileItemListPrope
containingDirs.size() == 1 ? tr("Pause %1").arg(containingDirs.front()->displayName()) : tr("Pause containing directories"),
parentWidget);
}
if (s_connection.isConnected()) {
if (connection.isConnected()) {
connect(actions.back(), &QAction::triggered,
bind(isPaused ? &SyncthingConnection::resumeDirectories : &SyncthingConnection::pauseDirectories, &s_connection, ids));
bind(isPaused ? &SyncthingConnection::resumeDirectories : &SyncthingConnection::pauseDirectories, &connection, ids));
} else {
actions.back()->setEnabled(false);
}
}
// don't add any further actions if no relevant actions could be determined so far
if (actions.isEmpty()) {
return actions;
}
// add actions to show further information about directory if the selection is only about one particular Syncthing dir
if (detectedDirs.size() + containingDirs.size() == 1) {
if (lastDir && detectedDirs.size() + containingDirs.size() == 1) {
auto *statusActions = new SyncthingDirActions(*lastDir, parentWidget);
connect(&s_connection, &SyncthingConnection::newDirs, statusActions,
connect(&connection, &SyncthingConnection::newDirs, statusActions,
static_cast<void (SyncthingDirActions::*)(const vector<SyncthingDir> &)>(&SyncthingDirActions::updateStatus));
connect(&s_connection, &SyncthingConnection::dirStatusChanged, statusActions,
connect(&connection, &SyncthingConnection::dirStatusChanged, statusActions,
static_cast<bool (SyncthingDirActions::*)(const SyncthingDir &)>(&SyncthingDirActions::updateStatus));
actions << *statusActions;
}
// add separator
if (!actions.isEmpty()) {
QAction *const separator = new QAction(parentWidget);
separator->setSeparator(true);
actions << separator;
}
// add error action
QAction *const errorAction = new SyncthingInfoAction(parentWidget);
errorAction->setText(data.currentError());
errorAction->setIcon(QIcon::fromTheme(QStringLiteral("state-error")));
errorAction->setVisible(data.hasError());
connect(&data, &SyncthingFileItemActionStaticData::currentErrorChanged, errorAction, &QAction::setText);
connect(&data, &SyncthingFileItemActionStaticData::hasErrorChanged, errorAction, &QAction::setVisible);
connect(&data, &SyncthingFileItemActionStaticData::currentErrorChanged, errorAction, &QAction::changed);
actions << errorAction;
// add config file selection
QAction *const configFileAction = new QAction(QIcon::fromTheme(QStringLiteral("settings-configure")), tr("Select Syncthing config ..."));
connect(configFileAction, &QAction::triggered, &data, &SyncthingFileItemActionStaticData::selectSyncthingConfig);
actions << configFileAction;
// about about action
QAction *separator = new QAction(parentWidget);
separator->setSeparator(true);
QAction *aboutAction = new QAction(QIcon::fromTheme(QStringLiteral("help-about")), tr("About"));
connect(aboutAction, &QAction::triggered, &SyncthingFileItemAction::showAboutDialog);
actions << separator << aboutAction;
QAction *const aboutAction = new QAction(QIcon::fromTheme(QStringLiteral("help-about")), tr("About"));
connect(aboutAction, &QAction::triggered, &SyncthingFileItemActionStaticData::showAboutDialog);
actions << aboutAction;
return actions;
}

View File

@ -6,9 +6,11 @@
#include <KAbstractFileItemActionPlugin>
#include <KFileItemListProperties>
#include <QAction>
#include <QWidget>
#include <QWidgetAction>
QT_FORWARD_DECLARE_CLASS(QWidget)
QT_FORWARD_DECLARE_CLASS(QLabel)
class KFileItemListProperties;
@ -16,8 +18,8 @@ class SyncthingMenuAction : public QAction {
Q_OBJECT
public:
SyncthingMenuAction(const KFileItemListProperties &properties = KFileItemListProperties(), const QList<QAction *> &actions = QList<QAction *>(),
QWidget *parentWidget = nullptr);
explicit SyncthingMenuAction(const KFileItemListProperties &properties = KFileItemListProperties(),
const QList<QAction *> &actions = QList<QAction *>(), QWidget *parentWidget = nullptr);
public Q_SLOTS:
void updateStatus(Data::SyncthingStatus status);
@ -26,11 +28,28 @@ 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:
SyncthingInfoAction(QObject *parent = nullptr);
explicit SyncthingInfoAction(QObject *parent = nullptr);
protected:
QWidget *createWidget(QWidget *parent) override;
@ -41,7 +60,7 @@ class SyncthingDirActions : public QObject {
friend QList<QAction *> &operator<<(QList<QAction *> &, SyncthingDirActions &);
public:
SyncthingDirActions(const Data::SyncthingDir &dir, QObject *parent = nullptr);
explicit SyncthingDirActions(const Data::SyncthingDir &dir, QObject *parent = nullptr);
public Q_SLOTS:
void updateStatus(const std::vector<Data::SyncthingDir> &dirs);
@ -60,23 +79,96 @@ private:
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
public:
SyncthingFileItemAction(QObject *parent, const QVariantList &args);
QList<QAction *> actions(const KFileItemListProperties &fileItemInfo, QWidget *parentWidget) override;
static Data::SyncthingConnection &connection();
static QList<QAction *> createActions(const KFileItemListProperties &fileItemInfo, QWidget *parentWidget);
private Q_SLOTS:
static void logConnectionStatus();
static void logConnectionError(const QString &errorMessage, Data::SyncthingErrorCategory errorCategory);
static void rescanDir(const QString &dirId, const QString &relpath = QString());
static void showAboutDialog();
static SyncthingFileItemActionStaticData &staticData();
private:
static Data::SyncthingConnection s_connection;
static SyncthingFileItemActionStaticData s_data;
};
inline SyncthingFileItemActionStaticData &SyncthingFileItemAction::staticData()
{
return s_data;
}
#endif // SYNCTHINGFILEITEMACTION_H