diff options
author | Martin Kampas <martin.kampas@jolla.com> | 2018-02-21 11:31:04 +0100 |
---|---|---|
committer | Svetlana Abramenkova <sabramenkova@luxoft.com> | 2018-06-14 08:11:51 +0000 |
commit | 4433fffbdec06241dcbb57c52c26d15bc4007e28 (patch) | |
tree | 11d2361a335acbcc2945d62cf5ac322b5fab427c | |
parent | 3e8e1de30c09fda84a66c31df1ac28ee33689ad1 (diff) |
Allow to limit the number of watched directories
Consider starting bench e.g. in home directory. Different limitation on
the number of watches applies depending on the platform. On linux the
limit is per-user.
Change-Id: If7a8cf6e3caa47ebaeb8cbd1fdc28d34d4d330b9
Reviewed-by: Svetlana Abramenkova <sabramenkova@luxoft.com>
-rw-r--r-- | src/bench/main.cpp | 14 | ||||
-rw-r--r-- | src/bench/mainwindow.cpp | 77 | ||||
-rw-r--r-- | src/bench/options.cpp | 11 | ||||
-rw-r--r-- | src/bench/options.h | 4 | ||||
-rw-r--r-- | src/livehubengine.cpp | 74 | ||||
-rw-r--r-- | src/livehubengine.h | 15 | ||||
-rw-r--r-- | src/watcher.cpp | 108 | ||||
-rw-r--r-- | src/watcher.h | 17 | ||||
-rw-r--r-- | src/widgets/workspaceview.cpp | 2 |
9 files changed, 301 insertions, 21 deletions
diff --git a/src/bench/main.cpp b/src/bench/main.cpp index 9336b33..bf12122 100644 --- a/src/bench/main.cpp +++ b/src/bench/main.cpp @@ -36,6 +36,7 @@ #include "hostmanager.h" #include "hostmodel.h" +#include "livehubengine.h" #include "options.h" #include "mainwindow.h" #include "qmllive_version.h" @@ -211,6 +212,8 @@ void Application::parseArguments(const QStringList &arguments, Options *options) parser.addOption(remoteOnlyOption); QCommandLineOption pingOption("ping", "just check if there is a bench running and accepting remote connections."); parser.addOption(pingOption); + QCommandLineOption maxWatchesOption("maxdirwatch", "limit the number of directories to watch for changes", "number", QString::number(options->maximumWatches())); + parser.addOption(maxWatchesOption); parser.process(arguments); @@ -237,6 +240,15 @@ void Application::parseArguments(const QStringList &arguments, Options *options) parser.showHelp(-1); } + if (parser.isSet(maxWatchesOption)) { + bool ok; + int value = parser.value(maxWatchesOption).toInt(&ok); + if (!ok) { + qWarning() << "Invalid argument to --maxdirwatch option"; + parser.showHelp(-1); + } + options->setMaximumWatches(value); + } options->setPluginPath(parser.value(pluginPathOption)); options->setImportPaths(parser.values(importPathOption)); @@ -417,6 +429,8 @@ void MasterApplication::listenForArguments() void MasterApplication::applyOptions(const Options &options) { + LiveHubEngine::setMaximumWatches(options.maximumWatches()); + if (!options.workspace().isEmpty()) m_window->setWorkspace(QDir(options.workspace()).absolutePath(), false); diff --git a/src/bench/mainwindow.cpp b/src/bench/mainwindow.cpp index 61924aa..bd7063a 100644 --- a/src/bench/mainwindow.cpp +++ b/src/bench/mainwindow.cpp @@ -49,6 +49,46 @@ #include "hostdiscoverymanager.h" #include "options.h" +class ErrorBar : public QFrame +{ + Q_OBJECT + +public: + ErrorBar(QWidget *parent = 0) + : QFrame(parent) + { + setFrameShape(QFrame::StyledPanel); + setAutoFillBackground(true); + QPalette p = palette(); + p.setColor(QPalette::Window, Qt::red); + setPalette(p); + + auto layout = new QHBoxLayout(this); + layout->setContentsMargins(4, 4, 4, 4); + + m_label = new QLabel; + m_label->setWordWrap(true); + layout->addWidget(m_label); + + auto button = new QToolButton; + button->setAutoRaise(true); + button->setIcon(QIcon(":images/refresh.svg")); + connect(button, &QAbstractButton::clicked, this, &ErrorBar::retry); + layout->addWidget(button); + } + + void setError(const QString &errorString) + { + m_label->setText(errorString); + setVisible(!errorString.isEmpty()); + } + +signals: + void retry(); + +private: + QLabel *m_label; +}; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) @@ -132,9 +172,42 @@ void MainWindow::setupWorkspaceView() { m_workspaceDock = new QDockWidget("Workspace", this); m_workspaceDock->setObjectName("workspace"); - m_workspaceDock->setWidget(m_workspace); m_workspaceDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); m_workspaceDock->setFeatures(QDockWidget::AllDockWidgetFeatures); + + auto contents = new QWidget; + auto layout = new QVBoxLayout(contents); + layout->setContentsMargins(1, 1, 1, 1); + layout->setSpacing(1); + + auto errorBar = new ErrorBar; + layout->addWidget(errorBar); + + auto updateErrorBar = [this, errorBar]() { + QString error; + switch (m_hub->error()) { + case LiveHubEngine::NoError: + break; + case LiveHubEngine::WatcherMaximumReached: + error = tr("Unable to monitor file changes: The configured limit of %1 directories was exceeded.") + .arg(LiveHubEngine::maximumWatches()); + break; + case LiveHubEngine::WatcherSystemError: + error = tr("Unable to monitor file changes. System limit exceeded?"); + break; + } + errorBar->setError(error); + }; + updateErrorBar(); + connect(m_hub, &LiveHubEngine::errorChanged, errorBar, updateErrorBar); + + connect(errorBar, &ErrorBar::retry, this, [this]() { + m_hub->setWorkspace(m_hub->workspace()); + }); + + layout->addWidget(m_workspace); + + m_workspaceDock->setWidget(contents); addDockWidget(Qt::LeftDockWidgetArea, m_workspaceDock); } @@ -517,3 +590,5 @@ void MainWindow::stayOnTop() } show(); } + +#include "mainwindow.moc" diff --git a/src/bench/options.cpp b/src/bench/options.cpp index 5baedc2..1e1f28b 100644 --- a/src/bench/options.cpp +++ b/src/bench/options.cpp @@ -37,6 +37,7 @@ Options::Options(QObject *parent) , m_remoteOnly(false) , m_ping(false) , m_stayOnTop(false) + , m_maximumWatches(100) { } @@ -174,3 +175,13 @@ void Options::setHostsToProbe(const QStringList &hostNames) { m_hostsToProbe = hostNames; } + +int Options::maximumWatches() const +{ + return m_maximumWatches; +} + +void Options::setMaximumWatches(int maximumWatches) +{ + m_maximumWatches = maximumWatches; +} diff --git a/src/bench/options.h b/src/bench/options.h index e7c84bd..a0ab44f 100644 --- a/src/bench/options.h +++ b/src/bench/options.h @@ -86,6 +86,9 @@ public: QStringList hostsToProbe() const; void setHostsToProbe(const QStringList &hostNames); + int maximumWatches() const; + void setMaximumWatches(int maximumWatches); + private: bool m_noRemote; bool m_remoteOnly; @@ -98,5 +101,6 @@ private: QList<HostOptions> m_hostsToAdd; QStringList m_hostsToRemove; QStringList m_hostsToProbe; + int m_maximumWatches; }; diff --git a/src/livehubengine.cpp b/src/livehubengine.cpp index 39208bf..91c65dc 100644 --- a/src/livehubengine.cpp +++ b/src/livehubengine.cpp @@ -48,6 +48,18 @@ */ /*! + \enum LiveHubEngine::Error + \brief Describes error state of an engine + + \value NoError + No error + \value WatcherMaximumReached + The maximum number of watches set with setMaximumWatches() was exceeded + \value WatcherSystemError + Watching a directory for changes failed for an unspecified reason + */ + +/*! * Standard constructor using \a parent as parent */ LiveHubEngine::LiveHubEngine(QObject *parent) @@ -56,6 +68,7 @@ LiveHubEngine::LiveHubEngine(QObject *parent) , m_filePublishingActive(false) { connect(m_watcher, &Watcher::directoriesChanged, this, &LiveHubEngine::directoriesChanged); + connect(m_watcher, &Watcher::errorChanged, this, &LiveHubEngine::watcherErrorChanged); } /*! @@ -95,6 +108,38 @@ LiveDocument LiveHubEngine::activePath() const } /*! + * Returns true if error() is not NoError + */ +bool LiveHubEngine::hasError() +{ + return m_error != NoError; +} + +/*! + * Returns current Error + */ +LiveHubEngine::Error LiveHubEngine::error() +{ + return m_error; +} + +/*! + * Returns the maximum number of watched directories + */ +int LiveHubEngine::maximumWatches() +{ + return Watcher::maximumWatches(); +} + +/*! + * Sets the maximum number of watched directories to \a maximumWatches + */ +void LiveHubEngine::setMaximumWatches(int maximumWatches) +{ + Watcher::setMaximumWatches(maximumWatches); +} + +/*! * Handles watcher changes signals. */ void LiveHubEngine::directoriesChanged(const QStringList &changes) @@ -110,6 +155,31 @@ void LiveHubEngine::directoriesChanged(const QStringList &changes) } /*! + * Handles watcher error signals + */ +void LiveHubEngine::watcherErrorChanged() +{ + Error newError = NoError; + switch (m_watcher->error()) { + case Watcher::NoError: + newError = NoError; + break; + case Watcher::MaximumReached: + newError = WatcherMaximumReached; + break; + case Watcher::SystemError: + newError = WatcherSystemError; + break; + } + + if (newError == m_error) + return; + + m_error = newError; + emit errorChanged(); +} + +/*! * Publish the whole workspace to a connected node. */ void LiveHubEngine::publishWorkspace() @@ -186,3 +256,7 @@ void LiveHubEngine::setFilePublishingActive(bool on) * The signal is emitted when the workspace identified by \a workspace has changed */ +/*! + * \fn void LiveHubEngine::errorChanged() + * The signal is emitted when the error state desctibed by error() changed + */ diff --git a/src/livehubengine.h b/src/livehubengine.h index 266e07e..eba7203 100644 --- a/src/livehubengine.h +++ b/src/livehubengine.h @@ -43,11 +43,23 @@ class QMLLIVESHARED_EXPORT LiveHubEngine : public QObject { Q_OBJECT public: + enum Error { + NoError, + WatcherMaximumReached, + WatcherSystemError, + }; + explicit LiveHubEngine(QObject *parent = 0); void setWorkspace(const QString& path); QString workspace() const; LiveDocument activePath() const; + + bool hasError(); + Error error(); + + static int maximumWatches(); + static void setMaximumWatches(int maximumWatches); public Q_SLOTS: void setActivePath(const LiveDocument& path); void setFilePublishingActive(bool on); @@ -59,13 +71,16 @@ Q_SIGNALS: void fileChanged(const LiveDocument& document); void activateDocument(const LiveDocument& document); void workspaceChanged(const QString& workspace); + void errorChanged(); private Q_SLOTS: void directoriesChanged(const QStringList& changes); + void watcherErrorChanged(); private: void publishDirectory(const QString& dirPath, bool fileChange); private: Watcher *m_watcher; bool m_filePublishingActive; LiveDocument m_activePath; + Error m_error = NoError; }; diff --git a/src/watcher.cpp b/src/watcher.cpp index 2be3abb..4bfb3b1 100644 --- a/src/watcher.cpp +++ b/src/watcher.cpp @@ -41,6 +41,20 @@ */ /*! + \enum Watcher::Error + \brief Describes error state of a Watcher + + \value NoError + No error + \value MaximumReached + The maximum number of watches set with setMaximumWatches() was exceeded + \value SystemError + QFileSystemWatcher::addPath failed for an unspecified reason + */ + +int Watcher::s_maximumWatches = -1; + +/*! Default Constructor using parent as parent */ Watcher::Watcher(QObject *parent) @@ -63,12 +77,8 @@ Watcher::Watcher(QObject *parent) void Watcher::setDirectory(const QString &path) { m_rootDir = QDir(path); - if (!m_watcher->directories().isEmpty()) { - m_watcher->removePaths(m_watcher->directories()); - } - if (!m_watcher->files().isEmpty()) { - m_watcher->removePaths(m_watcher->files()); - } + removeAllPaths(); + setError(NoError); addDirectoriesRecursively(m_rootDir.absolutePath()); } @@ -81,28 +91,90 @@ QString Watcher::directory() const } /*! + \fn Watcher::maximumWatches() + + Returns the maximum number of watched directories + */ + +/*! + Sets the maximum number of watched directories + + This will only take effect with next setDirectory() call. + */ +void Watcher::setMaximumWatches(int maximumWatches) +{ + s_maximumWatches = maximumWatches; +} + +/*! + \fn Watcher::hasError() const + + Returns true if error() is not NoError + */ + +/*! + \fn Watcher::error() const + + Describes the current error state of this watcher + */ + +/*! + \fn Watcher::errorChanged() + + Notifies about error() change + */ + +/*! Add path and all it's SubDirectory to the internal used QFileSystemWatcher */ void Watcher::addDirectoriesRecursively(const QString &path) { // qDebug() << "scan: " << path; - if (!m_watcher->directories().contains(path)) { - m_watcher->addPath(path); - } + addDirectory(path); QDirIterator iter(path, QDir::Dirs|QDir::NoDotAndDotDot, QDirIterator::Subdirectories); - while (iter.hasNext()) { + while (iter.hasNext() && !hasError()) { QDir entry(iter.next()); - if (!m_watcher->directories().contains(entry.absolutePath())) { - m_watcher->addPath(entry.absolutePath()); + addDirectory(entry.absolutePath()); + } +} - //If we couldn't add it we reached the filesystem limit - if (!m_watcher->directories().contains(entry.absolutePath())) { - qWarning() << "Watcher limit reached. Please reduce the number of files you are watching !!!"; - return; - } - } +void Watcher::addDirectory(const QString &path) +{ + if (m_watcher->directories().contains(path)) + return; + + if (s_maximumWatches > 0 && + m_watcher->directories().count() + m_watcher->files().count() > s_maximumWatches) { + removeAllPaths(); + setError(MaximumReached); + return; } + m_watcher->addPath(path); + + if (!m_watcher->directories().contains(path)) { + removeAllPaths(); + setError(SystemError); + } +} + +void Watcher::removeAllPaths() +{ + if (!m_watcher->directories().isEmpty()) { + m_watcher->removePaths(m_watcher->directories()); + } + if (!m_watcher->files().isEmpty()) { + m_watcher->removePaths(m_watcher->files()); + } +} + +void Watcher::setError(Watcher::Error error) +{ + if (m_error == error) + return; + + m_error = error; + emit errorChanged(); } void Watcher::recordChange(const QString &path) diff --git a/src/watcher.h b/src/watcher.h index a17e28a..434f552 100644 --- a/src/watcher.h +++ b/src/watcher.h @@ -37,20 +37,35 @@ class Watcher : public QObject { Q_OBJECT public: + enum Error { + NoError, + MaximumReached, + SystemError, + }; + explicit Watcher(QObject *parent = 0); void setDirectory(const QString& path); QString directory() const; + bool hasError() const { return m_error != NoError; } + Error error() const { return m_error; } + static int maximumWatches() { return s_maximumWatches; } + static void setMaximumWatches(int maximumWatches); private Q_SLOTS: void recordChange(const QString &path); void notifyChanges(); Q_SIGNALS: void directoriesChanged(const QStringList& changes); - + void errorChanged(); private: void addDirectoriesRecursively(const QString& path); + void addDirectory(const QString &path); + void removeAllPaths(); + void setError(Error error); + static int s_maximumWatches; QFileSystemWatcher *m_watcher; QDir m_rootDir; QTimer *m_waitTimer; QStringList m_changes; + Error m_error = NoError; }; diff --git a/src/widgets/workspaceview.cpp b/src/widgets/workspaceview.cpp index a1f26f8..44e621a 100644 --- a/src/widgets/workspaceview.cpp +++ b/src/widgets/workspaceview.cpp @@ -73,7 +73,7 @@ WorkspaceView::WorkspaceView(QWidget *parent) // setup layout QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(m_view); - layout->setMargin(1); + layout->setContentsMargins(0, 0, 0, 0); setLayout(layout); m_view->setDragEnabled(true); |