Allow opening dir in file browser if path contains tilde

See https://github.com/Martchus/syncthingtray/issues/148
This commit is contained in:
Martchus 2022-08-02 20:05:11 +02:00
parent ff2f435e4a
commit 788a5b2947
10 changed files with 90 additions and 9 deletions

View File

@ -427,6 +427,8 @@ void SyncthingConnection::continueReconnecting()
m_lastDiskEventId = 0;
m_configDir.clear();
m_myId.clear();
m_tilde.clear();
m_pathSeparator.clear();
m_totalIncomingTraffic = unknownTraffic;
m_totalOutgoingTraffic = unknownTraffic;
m_totalIncomingRate = 0.0;
@ -982,6 +984,19 @@ void SyncthingConnection::emitMyIdChanged(const QString &newId)
emit myIdChanged(m_myId = newId);
}
/*!
* \brief Internally called to emit tildeChanged() signal.
*/
void SyncthingConnection::emitTildeChanged(const QString &newTilde, const QString &newPathSeparator)
{
if ((newTilde.isEmpty() || m_tilde == newTilde) && (newPathSeparator.isEmpty() && m_pathSeparator == newPathSeparator)) {
return;
}
m_tilde = newTilde;
m_pathSeparator = newPathSeparator;
emit tildeChanged(m_tilde);
}
/*!
* \brief Internally called to emit dirStatisticsChanged() event.
*/
@ -1116,6 +1131,11 @@ void SyncthingConnection::recalculateStatus()
* \brief Indicates ID of the own Syncthing device changed.
*/
/*!
* \fn SyncthingConnection::tildeChanged()
* \brief Indicates the tilde or path separator of the connected Syncthing instance changed.
*/
/*!
* \fn SyncthingConnection::trafficChanged()
* \brief Indicates totalIncomingTraffic() or totalOutgoingTraffic() has changed.

View File

@ -94,6 +94,8 @@ class LIB_SYNCTHING_CONNECTOR_EXPORT SyncthingConnection : public QObject {
Q_PROPERTY(int devStatsPollInterval READ devStatsPollInterval WRITE setDevStatsPollInterval)
Q_PROPERTY(bool recordFileChanges READ recordFileChanges WRITE setRecordFileChanges)
Q_PROPERTY(QString myId READ myId NOTIFY myIdChanged)
Q_PROPERTY(QString tilde READ tilde NOTIFY tildeChanged)
Q_PROPERTY(QString pathSeparator READ pathSeparator NOTIFY tildeChanged)
Q_PROPERTY(QString configDir READ configDir NOTIFY configDirChanged)
Q_PROPERTY(quint64 totalIncomingTraffic READ totalIncomingTraffic NOTIFY trafficChanged)
Q_PROPERTY(quint64 totalOutgoingTraffic READ totalOutgoingTraffic NOTIFY trafficChanged)
@ -158,6 +160,8 @@ public:
// getter for information retrieved from Syncthing
const QString &configDir() const;
const QString &myId() const;
const QString &tilde() const;
const QString &pathSeparator() const;
std::uint64_t totalIncomingTraffic() const;
std::uint64_t totalOutgoingTraffic() const;
double totalIncomingRate() const;
@ -255,6 +259,7 @@ Q_SIGNALS:
void statusChanged(SyncthingStatus newStatus);
void configDirChanged(const QString &newConfigDir);
void myIdChanged(const QString &myNewId);
void tildeChanged(const QString &tilde);
void trafficChanged(std::uint64_t totalIncomingTraffic, std::uint64_t totalOutgoingTraffic);
void newConfigTriggered();
void rescanTriggered(const QString &dirId);
@ -327,6 +332,7 @@ private Q_SLOTS:
void emitError(const QString &message, const QJsonParseError &jsonError, QNetworkReply *reply, const QByteArray &response = QByteArray());
void emitError(const QString &message, SyncthingErrorCategory category, QNetworkReply *reply);
void emitMyIdChanged(const QString &newId);
void emitTildeChanged(const QString &newTilde, const QString &newPathSeparator);
void emitDirStatisticsChanged();
void handleFatalConnectionError();
void handleAdditionalRequestCanceled();
@ -376,6 +382,8 @@ private:
unsigned int m_autoReconnectTries;
QString m_configDir;
QString m_myId;
QString m_tilde;
QString m_pathSeparator;
std::uint64_t m_totalIncomingTraffic;
std::uint64_t m_totalOutgoingTraffic;
double m_totalIncomingRate;
@ -519,9 +527,9 @@ inline bool SyncthingConnection::isConnecting() const
* - Requests for (disk) events are excluded because those are long polling requests and therefore always pending.
* Instead, we take only into account whether those requests have been at least concluded once (since the last
* reconnect).
* - Only requests which contribute to the overall state and population of myId(), dirInfo(), devInfo(), traffic
* statistics, ... are considered. So requests for QR code, logs, clearing errors, rescan, ... are not taken
* into account.
* - Only requests which contribute to the overall state and population of myId(), tilde(), dirInfo(), devInfo(),
* traffic statistics, ... are considered. So requests for QR code, logs, clearing errors, rescan, ... are not
* taken into account.
* - This function will also return true as long as the method abortAllRequests() is executed.
*/
inline bool SyncthingConnection::hasPendingRequests() const
@ -729,6 +737,22 @@ inline const QString &SyncthingConnection::myId() const
return m_myId;
}
/*!
* \brief Returns the substitution for "~" of the Syncthing instance.
*/
inline const QString &SyncthingConnection::tilde() const
{
return m_tilde;
}
/*!
* \brief Returns the path separator of the Syncthing instance.
*/
inline const QString &SyncthingConnection::pathSeparator() const
{
return m_pathSeparator;
}
/*!
* \brief Returns the total incoming traffic in byte.
*/

View File

@ -699,7 +699,7 @@ void SyncthingConnection::readDevs(const QJsonArray &devs)
/*!
* \brief Requests the Syncthing status asynchronously.
*
* The signals myIdChanged() are emitted when those values have changed; error() is emitted in the error case.
* The signals myIdChanged() and tildeChanged() are emitted when those values have changed; error() is emitted in the error case.
*/
void SyncthingConnection::requestStatus()
{
@ -732,6 +732,7 @@ void SyncthingConnection::readStatus()
const auto replyObj = replyDoc.object();
emitMyIdChanged(replyObj.value(QLatin1String("myID")).toString());
emitTildeChanged(replyObj.value(QLatin1String("tilde")).toString(), replyObj.value(QLatin1String("pathSeparator")).toString());
m_startTime = parseTimeStamp(replyObj.value(QLatin1String("startTime")), QStringLiteral("start time"));
m_hasStatus = true;

View File

@ -139,6 +139,15 @@ void MiscTests::testUtils()
CPPUNIT_ASSERT(isLocal(QUrl(QStringLiteral("http://[::1]"))));
CPPUNIT_ASSERT(isLocal(QUrl(QStringLiteral("http://localhost/"))));
CPPUNIT_ASSERT(!isLocal(QUrl(QStringLiteral("http://157.3.52.34"))));
CPPUNIT_ASSERT_EQUAL(
QStringLiteral("/some/path"), substituteTilde(QStringLiteral("/some/path"), QStringLiteral("/home/foo"), QStringLiteral("/")));
CPPUNIT_ASSERT_EQUAL(
QStringLiteral("/home/foo/some/path"), substituteTilde(QStringLiteral("~/some/path"), QStringLiteral("/home/foo"), QStringLiteral("/")));
CPPUNIT_ASSERT_EQUAL(
QStringLiteral("~bar/some/path"), substituteTilde(QStringLiteral("~bar/some/path"), QStringLiteral("/home/foo"), QStringLiteral("/")));
CPPUNIT_ASSERT_EQUAL(QStringLiteral("/home/foobar/some/path"),
substituteTilde(QStringLiteral("~bar/some/path"), QStringLiteral("/home/foo"), QStringLiteral("bar/")));
CPPUNIT_ASSERT_EQUAL(QStringLiteral("/home/foo"), substituteTilde(QStringLiteral("~"), QStringLiteral("/home/foo"), QStringLiteral("\\")));
}
#ifdef LIB_SYNCTHING_CONNECTOR_SUPPORT_SYSTEMD

View File

@ -1,6 +1,8 @@
#include "./utils.h"
#include "./syncthingconnection.h"
#include <qtutilities/misc/compat.h>
#include <c++utilities/chrono/datetime.h>
#include <c++utilities/conversion/stringconversion.h>
@ -222,4 +224,22 @@ bool setDevicesPaused(QJsonObject &syncthingConfig, const QStringList &devIds, b
return altered;
}
/*!
* \brief Substitutes "~" as first element in \a path with \a tilde assuming the elements in \a path
* are separated by \a pathSeparator.
*/
QString substituteTilde(const QString &path, const QString &tilde, const QString &pathSeparator)
{
if (tilde.isEmpty() || pathSeparator.isEmpty() || !path.startsWith(QChar('~'))) {
return path;
}
if (path.size() < 2) {
return tilde;
}
if (QtUtilities::midRef(path, 1).startsWith(pathSeparator)) {
return tilde % pathSeparator % QtUtilities::midRef(path, 1 + pathSeparator.size());
}
return path;
}
} // namespace Data

View File

@ -37,6 +37,7 @@ LIB_SYNCTHING_CONNECTOR_EXPORT bool isLocal(const QString &hostName);
LIB_SYNCTHING_CONNECTOR_EXPORT bool isLocal(const QString &hostName, const QHostAddress &hostAddress);
LIB_SYNCTHING_CONNECTOR_EXPORT bool setDirectoriesPaused(QJsonObject &syncthingConfig, const QStringList &dirIds, bool paused);
LIB_SYNCTHING_CONNECTOR_EXPORT bool setDevicesPaused(QJsonObject &syncthingConfig, const QStringList &dirs, bool paused);
LIB_SYNCTHING_CONNECTOR_EXPORT QString substituteTilde(const QString &path, const QString &tilde, const QString &pathSeparator);
/*!
* \brief Returns whether the host specified by the given \a url is the local machine.

View File

@ -309,6 +309,11 @@ QString SyncthingApplet::formatFileSize(quint64 fileSizeInByte) const
return QString::fromStdString(dataSizeToString(fileSizeInByte));
}
QString SyncthingApplet::substituteTilde(const QString &path) const
{
return Data::substituteTilde(path, m_connection.tilde(), m_connection.pathSeparator());
}
void SyncthingApplet::showSettingsDlg()
{
if (!m_settingsDlg) {

View File

@ -136,6 +136,7 @@ public Q_SLOTS:
void updateStatusIconAndTooltip();
QIcon loadForkAwesomeIcon(const QString &name, int size = 32) const;
QString formatFileSize(quint64 fileSizeInByte) const;
QString substituteTilde(const QString &path) const;
Q_SIGNALS:
/// \remarks Never emitted, just to silence "... depends on non-NOTIFYable ..."

View File

@ -109,7 +109,7 @@ ColumnLayout {
icon.source: plasmoid.nativeInterface.faUrl + "folder"
tooltip: qsTr("Open in file browser")
onClicked: {
Qt.openUrlExternally(path)
Qt.openUrlExternally(plasmoid.nativeInterface.substituteTilde(path))
plasmoid.expanded = false
}
}

View File

@ -540,11 +540,11 @@ void TrayWidget::applySettingsOnAllInstances()
void TrayWidget::openDir(const SyncthingDir &dir)
{
if (QDir(dir.path).exists()) {
openLocalFileOrDir(dir.path);
const auto path = substituteTilde(dir.path, m_connection.tilde(), m_connection.pathSeparator());
if (QDir(path).exists()) {
openLocalFileOrDir(path);
} else {
QMessageBox::warning(
this, QCoreApplication::applicationName(), tr("The directory <i>%1</i> does not exist on the local machine.").arg(dir.path));
QMessageBox::warning(this, QCoreApplication::applicationName(), tr("The directory <i>%1</i> does not exist on the local machine.").arg(path));
}
}