aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@qt.io>2018-06-04 14:55:20 +0200
committerOswald Buddenhagen <oswald.buddenhagen@qt.io>2018-06-04 14:55:20 +0200
commit73b81cd379569f3fa54924738e00e35444ccbea4 (patch)
treed5c4b1392bd11318a0bec3f9543ffefab6164dda
parent4d360892c7a21b4b2aad0ec47ef3f60fb0b0b381 (diff)
parenta9449980b08e94ae648d38ea98e5e7a20fc9365e (diff)
Merge branch '5.8' into dev
Conflicts: qmllive.pro Change-Id: I14a957912a4caaf7a2d3734819d98097f79f2810
-rw-r--r--INSTALL.md4
-rw-r--r--doc/classes.qdoc100
-rw-r--r--doc/concepts.qdoc6
-rw-r--r--doc/examples/contentplugin.qdoc2
-rw-r--r--doc/index.qdoc12
-rw-r--r--doc/installation.qdoc16
-rw-r--r--doc/qmllive-group.qdoc7
-rw-r--r--doc/qmllive-online.qdocconf5
-rw-r--r--doc/qmllive-project.qdocconf20
-rw-r--r--doc/style/qt5-sidebar.html13
-rw-r--r--doc/usage.qdoc71
-rw-r--r--examples/app/app.pro1
-rw-r--r--examples/app/main.cpp66
-rwxr-xr-xqmllive.pro10
-rw-r--r--src/bench/aboutdialog.cpp2
-rw-r--r--src/bench/allhostswidget.cpp7
-rw-r--r--src/bench/allhostswidget.h4
-rw-r--r--src/bench/benchlivenodeengine.cpp6
-rw-r--r--src/bench/host.cpp13
-rw-r--r--src/bench/host.h15
-rw-r--r--src/bench/hostmanager.cpp24
-rw-r--r--src/bench/hostmanager.h5
-rw-r--r--src/bench/hostmodel.cpp18
-rw-r--r--src/bench/hostsoptionpage.cpp26
-rw-r--r--src/bench/hostwidget.cpp269
-rw-r--r--src/bench/hostwidget.h23
-rw-r--r--src/bench/importpathoptionpage.cpp6
-rw-r--r--src/bench/main.cpp20
-rw-r--r--src/bench/mainwindow.cpp111
-rw-r--r--src/bench/mainwindow.h5
-rw-r--r--src/bench/options.cpp4
-rw-r--r--src/bench/options.h8
-rw-r--r--src/bench/optionsdialog.cpp4
-rw-r--r--src/ipc/ipcclient.cpp42
-rw-r--r--src/ipc/ipcconnection.cpp7
-rw-r--r--src/ipc/ipcserver.cpp15
-rwxr-xr-xsrc/lib.pro2
-rw-r--r--src/livedocument.cpp193
-rw-r--r--src/livedocument.h67
-rw-r--r--src/livehubengine.cpp23
-rw-r--r--src/livehubengine.h13
-rw-r--r--src/livenodeengine.cpp215
-rw-r--r--src/livenodeengine.h17
-rw-r--r--src/liveruntime.cpp4
-rw-r--r--src/logreceiver.cpp2
-rw-r--r--src/previewGenerator/main.cpp4
-rw-r--r--src/qmlhelper.cpp6
-rwxr-xr-xsrc/qmllive_global.h24
-rw-r--r--src/remotelogger.cpp2
-rw-r--r--src/remotepublisher.cpp72
-rw-r--r--src/remotepublisher.h8
-rw-r--r--src/remotereceiver.cpp94
-rw-r--r--src/remotereceiver.h13
-rw-r--r--src/runtime/main.cpp9
-rw-r--r--src/src.pri2
-rw-r--r--src/watcher.cpp13
-rw-r--r--src/watcher.h1
-rw-r--r--src/widgets/filesystemmodel.cpp1
-rw-r--r--src/widgets/logview.cpp4
-rw-r--r--src/widgets/logview.h2
-rw-r--r--src/widgets/workspacedelegate.cpp35
-rw-r--r--src/widgets/workspacedelegate.h7
-rw-r--r--src/widgets/workspaceview.cpp31
-rw-r--r--src/widgets/workspaceview.h11
-rw-r--r--tests/testipc/tst_testipc.cpp8
65 files changed, 1241 insertions, 609 deletions
diff --git a/INSTALL.md b/INSTALL.md
index 225188b..9eb4fe7 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -25,9 +25,9 @@ target.
## Build documentation
- $ export QT_INSTALL_DOCS=$QTSRC/qtbase/doc
+ $ qmake CONFIG+=force_independent
$ make docs
-The documentation will be avilable at 'doc/html/index.html'.
+The documentation will be avilable at 'doc/qmllive/index.html'.
Copyright (C) 2016 Pelagicore AG
diff --git a/doc/classes.qdoc b/doc/classes.qdoc
deleted file mode 100644
index 952f2d9..0000000
--- a/doc/classes.qdoc
+++ /dev/null
@@ -1,100 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QmlLive tool.
-**
-** $QT_BEGIN_LICENSE:GPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) any later version
-** approved by the KDE Free Qt Foundation. The licenses are as published by
-** the Free Software Foundation and appearing in the file LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: GPL-3.0
-**
-****************************************************************************/
-
-/*!
- \group classlists
- \title Class and Function Documentation
- \brief Lists and Indexes of classes, functions, and types.
-
- Links to indexes and lists for finding class and function
- reference documentation.
-
- \section2 Class Lists
-
- \annotatedlist classlists
-
- \section2 Function Lists
-
- \annotatedlist funclists
-
-*/
-
-/*!
- \page classes.html
- \title All Classes
- \ingroup classlists
-
- \brief If you know the name of the class you want, find it here.
-
- This is a list of all Qt classes.
-
- \generatelist classes
-*/
-
-/*!
- \page hierarchy.html
-
- \title Inheritance Hierarchy
- \ingroup classlists
-
- \brief The C++ class inheritance hierarchy for all classes in the
- Qt API.
-
- \generatelist classhierarchy
-*/
-
-/*!
- \page functions.html
- \title All Functions
- \ingroup funclists
-
- \brief All documented Qt functions listed alphabetically with a
- link to their declarations.
-
- This is the list of all documented member functions and global
- functions in the Qt API. Each function has a link to the class or
- header file where it is declared and documented.
-
- \generatelist functionindex
-*/
-
-
-/*!
- \page namespaces.html
- \title All Namespaces
- \ingroup classlists
-
- \brief A Qt namespace contains enum types, functions, and sometimes classes.
-
- This is a list of the main namespaces in Qt.
-
- \generatelist{namespaces}
-*/
diff --git a/doc/concepts.qdoc b/doc/concepts.qdoc
index 527c696..73e1634 100644
--- a/doc/concepts.qdoc
+++ b/doc/concepts.qdoc
@@ -31,7 +31,7 @@
/*!
-\page concepts.html
+\page qmllive-concepts.html
\title Concepts
\chapter Live Reloading
@@ -87,8 +87,8 @@ display for the embedded device. There are subtle changes in the color
appearance, pixel density, font rendering and proportions. So it is vital to
ensure that a user experience designed on a PC looks just as brilliant on the
embedded device. In the past this was always cumbersome and required that you
-manually copy the code to the device and restart the application. With
-QmlLive and the QmlLive Runtime you simply connect to the device, propagate your
+manually copy the code to the device and restart the application. With QmlLive
+Bench and QmlLive Runtime you simply connect to the device, propagate your
workspace and from then on all changes are reflected on the device display. Of course,
you can also connect more devices, or devices with different sizes.
diff --git a/doc/examples/contentplugin.qdoc b/doc/examples/contentplugin.qdoc
index 870d466..a62267e 100644
--- a/doc/examples/contentplugin.qdoc
+++ b/doc/examples/contentplugin.qdoc
@@ -44,7 +44,7 @@
contentadapterinterface.h in the QmlLive source code. This
interface can be used to add a new ContentAdapter to QmlLive.
The ContentAdapter will be used to display any content that shouldn't be
- handled by the LiveRuntime, like displaying an image.
+ handled by the QmlLive Runtime, like displaying an image.
\snippet contentadapterinterface.h 0
diff --git a/doc/index.qdoc b/doc/index.qdoc
index 90eecb3..c560534 100644
--- a/doc/index.qdoc
+++ b/doc/index.qdoc
@@ -31,14 +31,14 @@
/*!
-\page index.html
-\keyword Pelagicore QML Live Reference Documentation
+\page qmllive-index.html
+\keyword Pelagicore QmlLive Reference Documentation
\indexpage
-\title Qt QML Live
+\title Qt QmlLive
\chapter Overview
-QmlLive is a local and remote QtQuick live reloading system. It allows you to
+Qt QmlLive is a local and remote Qt Quick live reloading system. It allows you to
change your QML user interface source code and view the result in almost
realtime.
@@ -68,7 +68,7 @@ The content of the documentation:
\li \l{Concepts} - General overview of the system
\li \l{qmllive-reference}{Reference} - The API reference to build your custom render scene
\list
- \li \l{qmllive}{QmlLive} - The QmlLIve library API
+ \li \l{qmllive}{QmlLive} - The QmlLive library API
\li \l{ipc}{IPC} - The internal IPC API
\endlist
@@ -79,7 +79,7 @@ The content of the documentation:
/*!
* \page qmllive-reference
- * \title Reference
+ * \title API Reference
*
*
* \list
diff --git a/doc/installation.qdoc b/doc/installation.qdoc
index bed44d8..bf552b4 100644
--- a/doc/installation.qdoc
+++ b/doc/installation.qdoc
@@ -31,7 +31,7 @@
/*!
-\page installation.html
+\page qmllive-installation.html
\title Installation
\chapter Dependencies
@@ -49,7 +49,7 @@
$ make
\endcode
-QML Live Bench can be started directly from build directory by executing
+QmlLive Bench can be started directly from build directory by executing
\c{./bin/qmllivebench}. Optionally it can be installed with
\code
@@ -81,11 +81,11 @@ Optionally it can be packaged with the help of
\chapter Building documentation
\code
- $ export QT_INSTALL_DOCS=$QTSRC/qtbase/doc
+ $ qmake CONFIG+=force_independent
$ make docs
\endcode
-The documentation will be available at \tt{doc/html/index.html}.
+The documentation will be available at \tt{doc/qmllive/index.html}.
\chapter Build options reference
@@ -99,7 +99,7 @@ The following values can be added to qmake \c CONFIG variable:
\row
\li skip-bench
- \li Do not build \l{Workbench}{QML Live Bench}
+ \li Do not build \l{The Workbench}{QmlLive Bench}
\row
\li skip-examples
@@ -107,7 +107,7 @@ The following values can be added to qmake \c CONFIG variable:
\row
\li skip-runtime
- \li Do not build \l{QmlLive Runtime}{QML Live Runtime}
+ \li Do not build \l{QmlLive Runtime}
\row
\li skip-tests
@@ -115,8 +115,8 @@ The following values can be added to qmake \c CONFIG variable:
\row
\li static-link-runtime
- \li Produce a single-binary QML Live Runtime executable. Without this option
- enabled QML Live Runtime executable requires the \c libqmllive dynamic
+ \li Produce a single-binary QmlLive Runtime executable. Without this option
+ enabled QmlLive Runtime executable requires the \c libqmllive dynamic
library to be copied to the target.
\endtable
diff --git a/doc/qmllive-group.qdoc b/doc/qmllive-group.qdoc
index 6f81e42..7c41db1 100644
--- a/doc/qmllive-group.qdoc
+++ b/doc/qmllive-group.qdoc
@@ -33,9 +33,10 @@
/*!
\module qmllive
- \title Live Module
- \brief Classes for watching a workspace and for local and remote reloading of QtQuick user interfaces
+ \title QmlLive Module
+ \brief Classes for watching a workspace and for local and remote reloading of Qt Quick user interfaces
- The live module allows a developer to quickly create his own instance of a workbench or a live runtime.
+ The QmlLive module allows a developer to quickly create his own instance of
+ a QmlLive workbench or a QmlLive runtime.
*/
diff --git a/doc/qmllive-online.qdocconf b/doc/qmllive-online.qdocconf
index 09b46fe..087139e 100644
--- a/doc/qmllive-online.qdocconf
+++ b/doc/qmllive-online.qdocconf
@@ -15,6 +15,9 @@ HTML.footer = \
include($QT_INSTALL_DOCS/global/qt-html-templates-online.qdocconf)
# Add an .html file with sidebar content, used in the online style
-# HTML.stylesheets += style/qt5-sidebar.html
+HTML.stylesheets += style/qt5-sidebar.html
+
+HTML.nosubdirs = "false"
+HTML.outputsubdir = "qmllive"
include(qmllive-project.qdocconf)
diff --git a/doc/qmllive-project.qdocconf b/doc/qmllive-project.qdocconf
index d93882b..5744d9f 100644
--- a/doc/qmllive-project.qdocconf
+++ b/doc/qmllive-project.qdocconf
@@ -1,6 +1,6 @@
-project = QML Live
-description = Pelagicore QML Live Reference Documentation
-url = https://doc.qt.io/QmlLive
+project = QmlLive
+description = Pelagicore QmlLive Reference Documentation
+url = https://doc.qt.io/QtQmlLive
version = $QT_VERSION
sources.fileextensions = "*.cpp *.qdoc *.mm *.qml"
@@ -14,7 +14,7 @@ exampledirs = ../examples ../src
headerdirs = \
../src
-sourcedirs = \
+sourcedirs += \
. \
../src \
../examples
@@ -25,17 +25,17 @@ qhp.projects = QmlLive
qhp.QmlLive.file = qmllive.qhp
qhp.QmlLive.namespace = io.qt.qmllive.$QT_VERSION_TAG
qhp.QmlLive.virtualFolder = qmllive
-qhp.QmlLive.indexTitle = Qt QML Live
+qhp.QmlLive.indexTitle = Qt QmlLive
qhp.QmlLive.indexRoot =
qhp.QmlLive.filterAttributes = QmlLive $QT_VERSION
-qhp.QmlLive.customFilters.QmlLive.name = QML Live $QT_VERSION
+qhp.QmlLive.customFilters.QmlLive.name = QmlLive $QT_VERSION
qhp.QmlLive.customFilters.QmlLive.filterAttributes = QmlLive $QT_VERSION
qhp.QmlLive.subprojects = manual
-qhp.QmlLive.subprojects.manual.title = Qt QML Live
-qhp.QmlLive.subprojects.manual.indexTitle = Qt QML Live
+qhp.QmlLive.subprojects.manual.title = Qt QmlLive
+qhp.QmlLive.subprojects.manual.indexTitle = Qt QmlLive
qhp.QmlLive.subprojects.manual.type = manual
-navigation.landingpage = "Qt QML Live"
-buildversion = "Qt QML Live $QT_VERSION"
+navigation.homepage = "Qt QmlLive"
+buildversion = "Qt QmlLive $QT_VERSION"
diff --git a/doc/style/qt5-sidebar.html b/doc/style/qt5-sidebar.html
new file mode 100644
index 0000000..7b6ce39
--- /dev/null
+++ b/doc/style/qt5-sidebar.html
@@ -0,0 +1,13 @@
+<div class="sectionlist normallist">
+ <div class="heading">
+ <h2>Qt QML Live</h2>
+ </div>
+ <ul>
+ <li><a href="index.html">Home</a></li>
+ <li><a href="qmllive-installation.html">Installation</a></li>
+ <li><a href="qmllive-usage.html">Usage</a></li>
+ <li><a href="qmllive-concepts.html">Concepts</a></li>
+ <li><a href="qmllive-reference.html">Reference</a></li>
+ <li><a href="qmllive-examples.html">Examples</a></li>
+ </ul>
+</div>
diff --git a/doc/usage.qdoc b/doc/usage.qdoc
index ed67e4a..3a669a6 100644
--- a/doc/usage.qdoc
+++ b/doc/usage.qdoc
@@ -31,7 +31,7 @@
/*!
-\page usage.html
+\page qmllive-usage.html
\title Usage
\chapter Introduction
@@ -40,75 +40,76 @@ The QmlLive system was designed from the ground up to support your needs. It is
structured in a modular fashion to be able to meet various usage
requirements.
-In the early phase of a project you normally want to use the \b QmlLiveBench,
+In the early phase of a project you normally want to use QmlLive \b Bench,
which has everything included in a typical desktop application.
Later in the project you may want to test your UI code on a device. For this we
-have designed the \b{QmlLiveBench} in combination with the
-\b{QmlLiveRuntime}. This combi pack offers you a default qml renderer to be run
+have designed the QmlLive Bench in combination with the
+QmlLive \b Runtime. This combi pack offers you a default QML renderer to be run
on the device and a small remote application on the desktop to control it.
For C++ developers, we also offer the ability to integrate the QmlLive
system into your own custom runtime using our \l LiveNodeEngine class with a few
-lines of code and then use the \b{QmlLiveRuntime} to implement it.
+lines of code and then use the QmlLive Bench to control it.
-\chapter Workbench
+\chapter The Workbench
-The standard workbench is the all inclusve qml live tool. It allows you to
-select a workspace to watch over and provides a default qml runtime for the
-active selected qml document.
+The standard workbench is the all inclusive QML live reloading tool. It allows you to
+select a workspace to watch over and provides a default QML runtime for the
+active selected QML document.
-\image workbench.png Workbench
+\image workbench.png The Workbench
You launch it by just executing the \tt qmllivebench executable
\code
-{$(QMLIVEPROJECT)/bin/qmllivebench[.exe]
+$(QMLIVEPROJECT)/bin/qmllivebench[.exe]
\endcode
-The QmlLive Bench can also be run from the command line
+The QmlLive Bench can also be passed a few command line arguments
\code
Usage qmllivebench [options] <workspace>
Usage qmllivebench [options] <workspace/file.qml>
options:
- -pluginpath ........................path to qmllive plugins
- -importpath ........................path to the qml import path
+ -pluginpath ........................path to QmlLive plugins
+ -importpath ........................path to the QML import path
-stayontop .........................keep viewer window on top
\endcode
-\chapter Creator Integration
+\chapter Qt Creator Integration
-You can integrate the QmlLiveBench into Qt Creator as an external tool. For this
-you need to open the Settings/Options dialog from QtCreator and open the
-\b{Environment} group. There you will find the \tt{External Tools} tab.
+You can integrate the QmlLive Bench into Qt Creator as an external tool. For this
+you need to open the Settings/Options dialog from Qt Creator and open the
+\uicontrol{Environment} group. There you will find the \uicontrol{External Tools} tab.
-Under exectuble enter the path of your QmlLiveBench executable.
+Under \uicontrol{Executable} enter the path to your QmlLive Bench executable.
-\image creator_tool.png Creator
+\image creator_tool.png Qt Creator
-Now QmlLiveBench is availabe under the menu entry \uicontrol{Tool->External->QmlLiveBench}.
-To be able to easier launch QmlLiveBench you can also assign a shortcut to the
+Now QmlLive Bench is availabe under the menu entry \uicontrol{Tool > External > QmlLive Bench}.
+To be able to easier launch QmlLive Bench you can also assign a shortcut to the
tool.
-\image creator_shortcut.png Creator
+\image creator_shortcut.png Qt Creator
-Now when you press \uicontrol{Alt-F8} QmlLiveBench will be launched with the current project root folder open as workspace.
+Now when you press \uicontrol{Alt-F8} QmlLive Bench will be launched with the
+current project root folder open as workspace.
-\image creator_result.png Creator
+\image creator_result.png Qt Creator
\chapter QmlLive Runtime
-The default runtime is meant to be used with the QmlLiveRuntime tool. It
-provides a default qml viewer and listens on a given port for ipc calls from
+A default runtime is provided by the QmlLive Runtime tool. It
+provides a default qml viewer and listens on a given port for IPC calls from
the remote. As such it's ideal to start developing on a target device, when no
extra c++ code is required.
-\image runtime.png Runtime
+\image runtime.png QmlLive Runtime
Calling the runtime
@@ -122,11 +123,11 @@ Usage of the runtime
Usage qmlliveruntime [options] <workspace>
options:
- -ipcport <port> ....................the port the ipc shall listen on
+ -ipcport <port> ....................the port the IPC shall listen on
-updates-as-overlay ................allow receiving updates with read only workspace
-update-on-connect .................update all workspace documents initially (blocking)
- -pluginpath ........................path to qmllive plugins
- -importpath ........................path to the qml import path
+ -pluginpath ........................path to QmlLive plugins
+ -importpath ........................path to the QML import path
-fullscreen ........................shows in fullscreen mode
-transparent .......................Make the window transparent
-frameless .........................run with no window frame
@@ -139,7 +140,7 @@ order to execute it. Receiving updates normally requires write access to the
deployed files. Depending on the target platform, the project may be deployed to
a location which is not user writable. In most cases hacking on the file
permissions after deployment can help, but a more convenient method is available
-- let the runtime store all updates in a writable workspace overlay. Use the \c
+- let QmlLive Runtime store all updates in a writable workspace overlay. Use the \c
-updates-as-overlay option to enable this feature.
Another constraints may exist on updating documents later after application
@@ -152,16 +153,16 @@ any QML component.
You can create your own custom runtime with the QmlLive features. This allows you to use your QML view setup with your additional C++ code together with the QmlLive system.
-For this you need to use the \b{LiveNodeEngine} class to be able to receive
+For this you need to use the \l LiveNodeEngine class to be able to receive
workspace changes and active document updates. By default, the IPC will listen
on the port 10234.
-Here is a short example of a minimal custom runtime:
+Here is a short example of a minimal custom QmlLive runtime:
\snippet ../examples/app/main.cpp 0
On platforms where pkg-config is supported simply add the following to your
-project file if QML Live is installed on your build host:
+project file if QmlLive is installed on your build host:
\code
CONFIG += link_pkgconfig
diff --git a/examples/app/app.pro b/examples/app/app.pro
index 3ffe5dc..cc41e36 100644
--- a/examples/app/app.pro
+++ b/examples/app/app.pro
@@ -1,5 +1,6 @@
TEMPLATE = app
TARGET = app
+CONFIG += c++11
macx*: CONFIG -= app_bundle
QT *= quick
diff --git a/examples/app/main.cpp b/examples/app/main.cpp
index 62b5d50..d02c60d 100644
--- a/examples/app/main.cpp
+++ b/examples/app/main.cpp
@@ -37,46 +37,96 @@
#include "livenodeengine.h"
#include "remotereceiver.h"
-class CustomQmlEngine : public QQmlEngine
+class MyQmlApplicationEngine : public QQmlApplicationEngine
{
Q_OBJECT
public:
- CustomQmlEngine(); // Perform some setup here
+ MyQmlApplicationEngine(const QString &mainQml); // Perform some setup here
+
+ QString mainQml() const;
+ QQuickWindow *mainWindow();
+ QList<QQmlError> warnings() const;
+
+ // ...
};
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
+ MyQmlApplicationEngine engine(QStringLiteral("qml/window.qml"));
- CustomQmlEngine qmlEngine;
- QQuickView fallbackView(&qmlEngine, 0);
+ if (!qEnvironmentVariableIsSet("MY_APP_ENABLE_QMLLIVE"))
+ return app.exec();
+#if defined(QT_NO_DEBUG)
+ qWarning() << "QmlLive support was disabled at compile time";
+#else
LiveNodeEngine node;
- // Let qml live know your runtime
- node.setQmlEngine(&qmlEngine);
+
+ // Let QmlLive know your runtime
+ node.setQmlEngine(&engine);
+
// Allow it to display QML components with non-QQuickWindow root object
+ QQuickView fallbackView(&engine, 0);
node.setFallbackView(&fallbackView);
+
// Tell it where file updates should be stored relative to
node.setWorkspace(app.applicationDirPath(),
LiveNodeEngine::AllowUpdates | LiveNodeEngine::UpdatesAsOverlay);
- // Listen to ipc call from remote QmlLiveBench
+
+ // Listen to IPC call from remote QmlLive Bench
RemoteReceiver receiver;
receiver.registerNode(&node);
receiver.listen(10234);
+ // Advanced use: let it know the initially loaded QML component (do this
+ // only after registering to receiver!)
+ node.usePreloadedDocument(engine.mainQml(), engine.mainWindow(), engine.warnings());
+#endif
+
return app.exec();
}
//![0]
-CustomQmlEngine::CustomQmlEngine()
+// Keep the snippet simple!
+static QString MyQmlApplicationEngine_mainQml;
+static QList<QQmlError> MyQmlApplicationEngine_warnings;
+
+MyQmlApplicationEngine::MyQmlApplicationEngine(const QString &mainQml)
{
+ // Would be nice to have this in QQmlApplicationEngine
+ MyQmlApplicationEngine_mainQml = mainQml;
+ connect(this, &QQmlEngine::warnings, [](const QList<QQmlError> &warnings) {
+ MyQmlApplicationEngine_warnings.append(warnings);
+ });
+
QStringList colors;
colors.append(QStringLiteral("red"));
colors.append(QStringLiteral("green"));
colors.append(QStringLiteral("blue"));
colors.append(QStringLiteral("black"));
rootContext()->setContextProperty("myColors", colors);
+
+ load(QDir(qApp->applicationDirPath()).absoluteFilePath(mainQml));
};
+QString MyQmlApplicationEngine::mainQml() const
+{
+ return MyQmlApplicationEngine_mainQml;
+}
+
+QQuickWindow *MyQmlApplicationEngine::mainWindow()
+{
+ if (rootObjects().isEmpty())
+ return nullptr;
+
+ return qobject_cast<QQuickWindow *>(rootObjects().first());
+}
+
+QList<QQmlError> MyQmlApplicationEngine::warnings() const
+{
+ return MyQmlApplicationEngine_warnings;
+}
+
#include "main.moc"
diff --git a/qmllive.pro b/qmllive.pro
index 21ed1aa..9aeb50f 100755
--- a/qmllive.pro
+++ b/qmllive.pro
@@ -1,4 +1,4 @@
-!CONFIG(skip-bench): requires(qtHaveModule(widgets))
+!skip-bench: requires(qtHaveModule(widgets))
requires(!winrt:!integrity)
load(configure)
@@ -6,14 +6,16 @@ load(config-output)
include(qmllive.pri)
include(doc/doc.pri)
-!minQtVersion(5, 4, 0):error("You need at least Qt 5.4.0 to build this application")
+!skip-bench:!minQtVersion(5, 4, 0): error("You need at least Qt 5.4.0 to build QmlLive Bench")
+!skip-tests:!minQtVersion(5, 4, 0): error("You need at least Qt 5.4.0 to build QmlLive tests")
+!minQtVersion(5, 2, 0): error("You need at least Qt 5.4.0 to build QmlLive Bench and/or tests, 5.2.0 for the rest")
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += src
-!CONFIG(skip-tests): SUBDIRS += tests
-!CONFIG(skip-examples): SUBDIRS += examples
+!skip-tests: SUBDIRS += tests
+!skip-examples: SUBDIRS += examples
OTHER_FILES += \
README.md \
diff --git a/src/bench/aboutdialog.cpp b/src/bench/aboutdialog.cpp
index ca6b3a5..c9c37bf 100644
--- a/src/bench/aboutdialog.cpp
+++ b/src/bench/aboutdialog.cpp
@@ -60,7 +60,7 @@ AboutDialog::AboutDialog(QWidget *parent)
#endif
QString about = tr(
- "<h3>Qt QML Live %1%2</h3>"
+ "<h3>Qt QmlLive %1%2</h3>"
"%3"
"<p>%4</p>"
"<p>The program is provided AS IS with NO WARRANTY OF ANY KIND, "
diff --git a/src/bench/allhostswidget.cpp b/src/bench/allhostswidget.cpp
index add6e0e..114eba7 100644
--- a/src/bench/allhostswidget.cpp
+++ b/src/bench/allhostswidget.cpp
@@ -31,6 +31,7 @@
#include "allhostswidget.h"
+#include "livedocument.h"
AllHostsWidget::AllHostsWidget(QWidget *parent) :
QWidget(parent)
@@ -38,11 +39,11 @@ AllHostsWidget::AllHostsWidget(QWidget *parent) :
setContentsMargins(0,0,0,0);
m_publishAction = new QAction("Publish", this);
m_publishAction->setIcon(QIcon(":images/publish.svg"));
- connect(m_publishAction, SIGNAL(triggered(bool)), this, SLOT(onPublishTriggered()));
+ connect(m_publishAction, &QAction::triggered, this, &AllHostsWidget::onPublishTriggered);
m_refreshAction = new QAction("Refresh", this);
m_refreshAction->setIcon(QIcon(":images/refresh.svg"));
- connect(m_refreshAction, SIGNAL(triggered(bool)), this, SIGNAL(refreshAll()));
+ connect(m_refreshAction, &QAction::triggered, this, &AllHostsWidget::refreshAll);
setAcceptDrops(true);
@@ -95,6 +96,6 @@ void AllHostsWidget::dropEvent(QDropEvent *event)
QUrl url(event->mimeData()->text());
if (url.isLocalFile())
- emit currentFileChanged(url.toLocalFile());
+ emit currentFileChanged(LiveDocument::resolve(m_workspace, url.toLocalFile()));
event->acceptProposedAction();
}
diff --git a/src/bench/allhostswidget.h b/src/bench/allhostswidget.h
index 47f4460..a53785f 100644
--- a/src/bench/allhostswidget.h
+++ b/src/bench/allhostswidget.h
@@ -33,6 +33,8 @@
#include <QtWidgets>
+class LiveDocument;
+
class AllHostsWidget : public QWidget
{
Q_OBJECT
@@ -44,7 +46,7 @@ public:
signals:
void refreshAll();
void publishAll();
- void currentFileChanged(const QString file);
+ void currentFileChanged(const LiveDocument &file);
protected:
void dropEvent(QDropEvent *event);
diff --git a/src/bench/benchlivenodeengine.cpp b/src/bench/benchlivenodeengine.cpp
index abe1910..30dd5b5 100644
--- a/src/bench/benchlivenodeengine.cpp
+++ b/src/bench/benchlivenodeengine.cpp
@@ -108,7 +108,11 @@ void BenchLiveNodeEngine::initPlugins()
DirectoryPreviewAdapter *adapter = new DirectoryPreviewAdapter(this);
if (m_workspaceView) {
//This needs to be QueuedConnection because Qt5 doesn't like it to destruct it's object while it is in a signalHandler
- connect(adapter, SIGNAL(loadDocument(QString)), m_workspaceView, SLOT(activateDocument(QString)), Qt::QueuedConnection);
+ connect(adapter, &DirectoryPreviewAdapter::loadDocument,
+ this, [this](const QString &document) {
+ m_workspaceView->activateDocument(LiveDocument(document));
+ },
+ Qt::QueuedConnection);
}
QmlPreviewAdapter *previewAdapter = new QmlPreviewAdapter(this);
diff --git a/src/bench/host.cpp b/src/bench/host.cpp
index fb1f366..2103e43 100644
--- a/src/bench/host.cpp
+++ b/src/bench/host.cpp
@@ -73,7 +73,7 @@ QString Host::address() const
return m_address;
}
-QString Host::currentFile() const
+LiveDocument Host::currentFile() const
{
return m_currentFile;
}
@@ -109,7 +109,7 @@ void Host::setAddress(QString arg)
}
}
-void Host::setCurrentFile(QString arg)
+void Host::setCurrentFile(LiveDocument arg)
{
m_currentFile = arg;
emit currentFileChanged(arg);
@@ -144,6 +144,8 @@ void Host::setOnline(bool arg)
if (m_online != arg) {
m_online = arg;
emit onlineChanged(arg);
+ if (m_type == AutoDiscovery)
+ emit availableChanged(arg);
}
}
@@ -191,6 +193,11 @@ bool Host::online() const
return m_online;
}
+bool Host::available() const
+{
+ return m_type == Manual || m_online;
+}
+
bool Host::followTreeSelection() const
{
return m_followTreeSelection;
@@ -208,7 +215,6 @@ void Host::saveToSettings(QSettings *s)
s->setValue("xOffset", xOffset());
s->setValue("yOffset", yOffset());
s->setValue("rotation", rotation());
- s->setValue("currentFile", currentFile());
s->setValue("autoDiscoveryId", autoDiscoveryId().toString());
s->setValue("systemName", systemName());
s->setValue("productVersion", productVersion());
@@ -226,7 +232,6 @@ void Host::restoreFromSettings(QSettings *s)
setXOffset(s->value("xOffset").toInt());
setYOffset(s->value("yOffset").toInt());
setRotation(s->value("rotation").toInt());
- setCurrentFile(s->value("currentFile").toString());
setAutoDiscoveryId(QUuid(s->value("autoDiscoveryId").toString()));
setSystemName(s->value("systemName").toString());
setProductVersion(s->value("productVersion").toString());
diff --git a/src/bench/host.h b/src/bench/host.h
index 658303c..0e7d1bb 100644
--- a/src/bench/host.h
+++ b/src/bench/host.h
@@ -31,6 +31,8 @@
#pragma once
+#include "livedocument.h"
+
#include <QObject>
#include <QUuid>
#include <QMetaType>
@@ -51,11 +53,12 @@ public:
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QString address READ address WRITE setAddress NOTIFY addressChanged)
Q_PROPERTY(int port READ port WRITE setPort NOTIFY portChanged)
- Q_PROPERTY(QString currentFile READ currentFile WRITE setCurrentFile NOTIFY currentFileChanged)
+ Q_PROPERTY(LiveDocument currentFile READ currentFile WRITE setCurrentFile NOTIFY currentFileChanged)
Q_PROPERTY(int xOffset READ xOffset WRITE setXOffset NOTIFY xOffsetChanged)
Q_PROPERTY(int yOffset READ yOffset WRITE setYOffset NOTIFY yOffsetChanged)
Q_PROPERTY(int rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
Q_PROPERTY(bool online READ online WRITE setOnline NOTIFY onlineChanged)
+ Q_PROPERTY(bool available READ available NOTIFY availableChanged)
Q_PROPERTY(bool followTreeSelection READ followTreeSelection WRITE setFollowTreeSelection NOTIFY followTreeSelectionChanged)
Q_PROPERTY(QUuid autoDiscoveryId READ autoDiscoveryId WRITE setAutoDiscoveryId NOTIFY autoDiscoveryIdChanged)
Q_PROPERTY(QString productVersion READ productVersion WRITE setProductVersion)
@@ -67,13 +70,14 @@ public:
QString name() const;
QString address() const;
int port() const;
- QString currentFile() const;
+ LiveDocument currentFile() const;
int xOffset() const;
int yOffset() const;
int rotation() const;
Type type() const;
bool online() const;
+ bool available() const;
bool followTreeSelection() const;
QUuid autoDiscoveryId() const;
QString productVersion() const;
@@ -88,11 +92,12 @@ signals:
void nameChanged(QString arg);
void addressChanged(QString arg);
void portChanged(int arg);
- void currentFileChanged(QString arg);
+ void currentFileChanged(LiveDocument arg);
void xOffsetChanged(int arg);
void yOffsetChanged(int arg);
void rotationChanged(int arg);
void onlineChanged(bool arg);
+ void availableChanged(bool arg);
void followTreeSelectionChanged(bool arg);
void autoDiscoveryIdChanged(QUuid arg);
@@ -102,7 +107,7 @@ public slots:
void setName(QString arg);
void setAddress(QString arg);
void setPort(int arg);
- void setCurrentFile(QString arg);
+ void setCurrentFile(LiveDocument arg);
void setXOffset(int arg);
void setYOffset(int arg);
void setRotation(int arg);
@@ -117,7 +122,7 @@ private:
QString m_name;
QString m_address;
int m_port;
- QString m_currentFile;
+ LiveDocument m_currentFile;
int m_xOffset;
int m_yOffset;
int m_rotation;
diff --git a/src/bench/hostmanager.cpp b/src/bench/hostmanager.cpp
index c48937e..633bfcd 100644
--- a/src/bench/hostmanager.cpp
+++ b/src/bench/hostmanager.cpp
@@ -36,9 +36,10 @@
#include "livehubengine.h"
#include "logreceiver.h"
#include "widgets/logview.h"
-#include <QDockWidget>
+#include <QDockWidget>
#include <QDebug>
+#include <QFileInfo>
HostManager::HostManager(QWidget *parent) :
QListView(parent)
@@ -67,7 +68,7 @@ void HostManager::setModel(HostModel *model)
m_model = model;
QListView::setModel(model);
- connect(model, SIGNAL(modelReset()), this, SLOT(modelReseted()));
+ connect(model, &HostModel::modelReset, this, &HostManager::modelReseted);
}
void HostManager::setLiveHubEngine(LiveHubEngine *engine)
@@ -81,8 +82,11 @@ void HostManager::setLiveHubEngine(LiveHubEngine *engine)
}
}
-void HostManager::followTreeSelection(const QString &currentFile)
+void HostManager::followTreeSelection(const LiveDocument &currentFile)
{
+ if (!currentFile.isFileIn(m_engine->workspace()))
+ return;
+
for (int i=0; i < m_model->rowCount(); i++) {
HostWidget *widget = qobject_cast<HostWidget*>(indexWidget(m_model->index(i, 0)));
if (widget && widget->followTreeSelection())
@@ -90,8 +94,11 @@ void HostManager::followTreeSelection(const QString &currentFile)
}
}
-void HostManager::setCurrentFile(const QString &currentFile)
+void HostManager::setCurrentFile(const LiveDocument &currentFile)
{
+ if (!currentFile.isFileIn(m_engine->workspace()))
+ return;
+
for (int i=0; i < m_model->rowCount(); i++) {
HostWidget *widget = qobject_cast<HostWidget*>(indexWidget(m_model->index(i, 0)));
if (widget)
@@ -147,14 +154,15 @@ void HostManager::addHost(int index)
widget->setLiveHubEngine(m_engine.data());
widget->setHost(host);
setIndexWidget(m_model->index(index,0), widget);
- connect(widget, SIGNAL(openHostConfig(Host*)), this, SIGNAL(openHostConfig(Host*)));
+ connect(widget, &HostWidget::openHostConfig, this, &HostManager::openHostConfig);
QDockWidget *dock = new QDockWidget(host->name());
dock->setObjectName(host->name() + "LogDock");
- connect(host, SIGNAL(nameChanged(QString)), dock, SLOT(setWindowTitle(QString)));
+ connect(host, &Host::nameChanged, dock, &QDockWidget::setWindowTitle);
LogView *view = new LogView(false, dock);
- connect(widget, SIGNAL(remoteLog(int,QString,QUrl,int,int)), view, SLOT(appendToLog(int,QString,QUrl,int,int)));
- connect(widget, SIGNAL(clearLog()), view, SLOT(clear()));
+ connect(widget, &HostWidget::remoteLog, view, &LogView::appendToLog);
+ connect(widget, &HostWidget::clearLog, view, &LogView::clear);
+ connect(widget, &HostWidget::connected, view, &LogView::clear);
dock->setWidget(view);
m_logList.append(dock);
emit logWidgetAdded(dock);
diff --git a/src/bench/hostmanager.h b/src/bench/hostmanager.h
index f37b915..68f241e 100644
--- a/src/bench/hostmanager.h
+++ b/src/bench/hostmanager.h
@@ -34,6 +34,7 @@
#include <QListView>
#include <QPointer>
+class LiveDocument;
class LiveHubEngine;
class HostModel;
class Host;
@@ -54,8 +55,8 @@ signals:
void openHostConfig(Host* host);
public slots:
- void followTreeSelection(const QString& currentFile);
- void setCurrentFile(const QString& currentFile);
+ void followTreeSelection(const LiveDocument& currentFile);
+ void setCurrentFile(const LiveDocument& currentFile);
void publishAll();
void refreshAll();
void probe(const QString &hostName);
diff --git a/src/bench/hostmodel.cpp b/src/bench/hostmodel.cpp
index a253614..98c102e 100644
--- a/src/bench/hostmodel.cpp
+++ b/src/bench/hostmodel.cpp
@@ -100,15 +100,15 @@ void HostModel::addHost(Host *host)
beginInsertRows(QModelIndex(), m_hosts.count(), m_hosts.count());
m_hosts.append(host);
- connect(host, SIGNAL(nameChanged(QString)), this, SLOT(onHostChanged()));
- connect(host, SIGNAL(addressChanged(QString)), this, SLOT(onHostChanged()));
- connect(host, SIGNAL(portChanged(int)), this, SLOT(onHostChanged()));
- connect(host, SIGNAL(followTreeSelectionChanged(bool)), this, SLOT(onHostChanged()));
- connect(host, SIGNAL(currentFileChanged(QString)), this, SLOT(onHostChanged()));
- connect(host, SIGNAL(xOffsetChanged(int)), this, SLOT(onHostChanged()));
- connect(host, SIGNAL(yOffsetChanged(int)), this, SLOT(onHostChanged()));
- connect(host, SIGNAL(rotationChanged(int)), this, SLOT(onHostChanged()));
- connect(host, SIGNAL(onlineChanged(bool)), this, SLOT(onHostChanged()));
+ connect(host, &Host::nameChanged, this, &HostModel::onHostChanged);
+ connect(host, &Host::addressChanged, this, &HostModel::onHostChanged);
+ connect(host, &Host::portChanged, this, &HostModel::onHostChanged);
+ connect(host, &Host::followTreeSelectionChanged, this, &HostModel::onHostChanged);
+ connect(host, &Host::currentFileChanged, this, &HostModel::onHostChanged);
+ connect(host, &Host::xOffsetChanged, this, &HostModel::onHostChanged);
+ connect(host, &Host::yOffsetChanged, this, &HostModel::onHostChanged);
+ connect(host, &Host::rotationChanged, this, &HostModel::onHostChanged);
+ connect(host, &Host::onlineChanged, this, &HostModel::onHostChanged);
endInsertRows();
}
diff --git a/src/bench/hostsoptionpage.cpp b/src/bench/hostsoptionpage.cpp
index e463b44..c7ac997 100644
--- a/src/bench/hostsoptionpage.cpp
+++ b/src/bench/hostsoptionpage.cpp
@@ -48,20 +48,26 @@ HostsOptionsPage::HostsOptionsPage(QWidget *parent) :
ui->hostUI->setVisible(false);
- connect(ui->nameField, SIGNAL(textEdited(QString)), this, SLOT(updateName(QString)));
- connect(ui->ipField, SIGNAL(textEdited(QString)), this, SLOT(updateAddress(QString)));
- connect(ui->portField, SIGNAL(valueChanged(int)), this, SLOT(updatePort(int)));
- connect(ui->followTreeSelectionField, SIGNAL(clicked(bool)), this, SLOT(updateFollowTreeSelection(bool)));
- connect(ui->xField, SIGNAL(valueChanged(int)), this, SLOT(updateXOffset(int)));
- connect(ui->yField, SIGNAL(valueChanged(int)), this, SLOT(updateYOffset(int)));
- connect(ui->rotationField, SIGNAL(valueChanged(int)), this, SLOT(updateRotation(int)));
+ connect(ui->nameField, &QLineEdit::textEdited, this, &HostsOptionsPage::updateName);
+ connect(ui->ipField, &QLineEdit::textEdited, this, &HostsOptionsPage::updateAddress);
+ void (QSpinBox::*QSpinBox__valueChanged)(int) = &QSpinBox::valueChanged;
+ connect(ui->portField, QSpinBox__valueChanged, this, &HostsOptionsPage::updatePort);
+ connect(ui->followTreeSelectionField, &QCheckBox::clicked, this, &HostsOptionsPage::updateFollowTreeSelection);
+ connect(ui->xField, QSpinBox__valueChanged, this, &HostsOptionsPage::updateXOffset);
+ connect(ui->yField, QSpinBox__valueChanged, this, &HostsOptionsPage::updateYOffset);
+ connect(ui->rotationField, QSpinBox__valueChanged, this, &HostsOptionsPage::updateRotation);
QMenu *menu = new QMenu(ui->addHostButton);
+#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
menu->addAction("Auto Discovery...", this, SLOT(showAutoDiscoveryDialog()));
menu->addAction("Manual", this, SLOT(addHost()));
+#else
+ menu->addAction("Auto Discovery...", this, &HostsOptionsPage::showAutoDiscoveryDialog);
+ menu->addAction("Manual", this, [this] { addHost(); });
+#endif
ui->addHostButton->setMenu(menu);
- connect(ui->removeHostButton, SIGNAL(clicked()), this, SLOT(removeHost()));
+ connect(ui->removeHostButton, &QAbstractButton::clicked, this, &HostsOptionsPage::removeHost);
}
HostsOptionsPage::~HostsOptionsPage()
@@ -74,8 +80,8 @@ void HostsOptionsPage::setHostModel(HostModel *model)
m_model = model;
m_currentIndex = -1;
- connect(ui->hostsWidget->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
- this, SLOT(onCurrentRowChanged(QModelIndex,QModelIndex)));
+ connect(ui->hostsWidget->selectionModel(), &QItemSelectionModel::currentRowChanged,
+ this, &HostsOptionsPage::onCurrentRowChanged);
for (int i=0; i< m_model->rowCount(); i++) {
Host *host = m_model->hostAt(i);
diff --git a/src/bench/hostwidget.cpp b/src/bench/hostwidget.cpp
index 0da4f24..804de9b 100644
--- a/src/bench/hostwidget.cpp
+++ b/src/bench/hostwidget.cpp
@@ -34,6 +34,10 @@
#include "host.h"
#include "livehubengine.h"
+#include <QMessageBox>
+
+Q_DECLARE_LOGGING_CATEGORY(csLog)
+Q_LOGGING_CATEGORY(csLog, "QmlLive.Bench.ConnectionState", QtInfoMsg)
const int LABEL_STACK_INDEX=0;
const int PROGRESS_STACK_INDEX=1;
@@ -46,15 +50,15 @@ HostWidget::HostWidget(QWidget *parent) :
m_connectDisconnectAction = new QAction("Offline", this);
m_connectDisconnectAction->setIcon(QIcon(":images/error_ball.svg"));
- connect(m_connectDisconnectAction, SIGNAL(triggered(bool)), this, SLOT(connectAndSendFile()));
+ connect(m_connectDisconnectAction, &QAction::triggered, this, &HostWidget::connectToServer);
m_refreshAction = new QAction("Refresh", this);
m_refreshAction->setIcon(QIcon(":images/refresh.svg"));
- connect(m_refreshAction, SIGNAL(triggered(bool)), this, SLOT(refresh()));
+ connect(m_refreshAction, &QAction::triggered, this, &HostWidget::refresh);
m_publishAction = new QAction("Publish", this);
m_publishAction->setIcon(QIcon(":/images/publish.svg"));
- connect(m_publishAction, SIGNAL(triggered(bool)), this, SLOT(publishAll()));
+ connect(m_publishAction, &QAction::triggered, this, &HostWidget::publishAll);
m_followTreeSelectionAction = new QAction("Follow", this);
m_followTreeSelectionAction->setIcon(QIcon(":images/linked.svg"));
@@ -62,7 +66,7 @@ HostWidget::HostWidget(QWidget *parent) :
m_editHostAction = new QAction("Setup", this);
m_editHostAction->setIcon(QIcon(":images/edit.svg"));
- connect(m_editHostAction, SIGNAL(triggered(bool)), this, SLOT(onEditHost()));
+ connect(m_editHostAction, &QAction::triggered, this, &HostWidget::onEditHost);
QGridLayout *layout = new QGridLayout(this);
layout->setContentsMargins(0,0,0,0);
@@ -99,46 +103,43 @@ HostWidget::HostWidget(QWidget *parent) :
vbox->addWidget(toolBar);;
- connect(&m_publisher, SIGNAL(connected()), this, SIGNAL(connected()));
- connect(&m_publisher, SIGNAL(connected()), this, SLOT(onConnected()));
- connect(&m_publisher, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
- connect(&m_publisher, SIGNAL(connectionError(QAbstractSocket::SocketError)),
- this, SLOT(onConnectionError(QAbstractSocket::SocketError)));
- connect(&m_publisher, SIGNAL(sendingError(QUuid,QAbstractSocket::SocketError)),
- this, SLOT(onSendingError(QUuid,QAbstractSocket::SocketError)));
- connect(&m_publisher, SIGNAL(sentSuccessfully(QUuid)),
- this, SLOT(onSentSuccessfully(QUuid)));
- connect(&m_publisher, SIGNAL(needsPinAuthentication()), this, SLOT(showPinDialog()));
- connect(&m_publisher, SIGNAL(pinOk(bool)), this, SLOT(onPinOk(bool)));
- connect(&m_publisher, SIGNAL(remoteLog(int,QString,QUrl,int,int)),
- this, SIGNAL(remoteLog(int,QString,QUrl,int,int)));
- connect(&m_publisher, SIGNAL(clearLog()), this, SIGNAL(clearLog()));
-
- onDisconnected();
+ connect(&m_publisher, &RemotePublisher::connected, this, &HostWidget::connected);
+ connect(&m_publisher, &RemotePublisher::connected, this, &HostWidget::onConnected);
+ connect(&m_publisher, &RemotePublisher::disconnected, this, &HostWidget::onDisconnected);
+ connect(&m_publisher, &RemotePublisher::connectionError, this, &HostWidget::onConnectionError);
+ connect(&m_publisher, &RemotePublisher::sendingError, this, &HostWidget::onSendingError);
+ connect(&m_publisher, &RemotePublisher::sentSuccessfully, this, &HostWidget::onSentSuccessfully);
+ connect(&m_publisher, &RemotePublisher::needsPinAuthentication, this, &HostWidget::showPinDialog);
+ connect(&m_publisher, &RemotePublisher::pinOk, this, &HostWidget::onPinOk);
+ connect(&m_publisher, &RemotePublisher::remoteLog, this, &HostWidget::remoteLog);
+ connect(&m_publisher, &RemotePublisher::clearLog, this, &HostWidget::clearLog);
}
void HostWidget::setHost(Host *host)
{
m_host = host;
- updateName(m_host->name());
- updateIp(m_host->address());
+ updateTitle();
updateFile(m_host->currentFile());
- updateOnlineState(m_host->online());
m_followTreeSelectionAction->setChecked(m_host->followTreeSelection());
- connect(host, SIGNAL(addressChanged(QString)), this, SLOT(updateIp(QString)));
- connect(host, SIGNAL(portChanged(int)), this, SLOT(updatePort(int)));
- connect(host, SIGNAL(onlineChanged(bool)), this, SLOT(updateOnlineState(bool)));
- connect(host, SIGNAL(currentFileChanged(QString)), this, SLOT(updateFile(QString)));
- connect(host, SIGNAL(nameChanged(QString)), this, SLOT(updateName(QString)));
- connect(host, SIGNAL(xOffsetChanged(int)), this, SLOT(sendXOffset(int)));
- connect(host, SIGNAL(yOffsetChanged(int)), this, SLOT(sendYOffset(int)));
- connect(host, SIGNAL(rotationChanged(int)), this, SLOT(sendRotation(int)));
- connect(host, SIGNAL(followTreeSelectionChanged(bool)),
- m_followTreeSelectionAction, SLOT(setChecked(bool)));
+ connect(host, &Host::addressChanged, this, &HostWidget::updateTitle);
+ connect(host, &Host::addressChanged, this, &HostWidget::scheduleConnectToServer);
+ connect(host, &Host::portChanged, this, &HostWidget::updateTitle);
+ connect(host, &Host::portChanged, this, &HostWidget::scheduleConnectToServer);
+ connect(host, &Host::availableChanged, this, &HostWidget::updateAvailableState);
+ connect(host, &Host::currentFileChanged, this, &HostWidget::updateFile);
+ connect(host, &Host::nameChanged, this, &HostWidget::updateTitle);
+ connect(host, &Host::xOffsetChanged, this, &HostWidget::sendXOffset);
+ connect(host, &Host::yOffsetChanged, this, &HostWidget::sendYOffset);
+ connect(host, &Host::rotationChanged, this, &HostWidget::sendRotation);
+ connect(host, &Host::followTreeSelectionChanged, this, &HostWidget::updateFollowTreeSelection);
- connect(m_followTreeSelectionAction, SIGNAL(triggered(bool)), host, SLOT(setFollowTreeSelection(bool)));
+ connect(m_followTreeSelectionAction, &QAction::triggered, host, &Host::setFollowTreeSelection);
+ connect(&m_publisher, &RemotePublisher::activeDocumentChanged, host, &Host::setCurrentFile);
+
+ updateAvailableState(m_host->available());
+ updateRemoteActions();
}
void HostWidget::setLiveHubEngine(LiveHubEngine *engine)
@@ -147,16 +148,20 @@ void HostWidget::setLiveHubEngine(LiveHubEngine *engine)
m_publisher.setWorkspace(m_engine->workspace());
- connect(m_engine.data(), SIGNAL(workspaceChanged(QString)), &m_publisher, SLOT(setWorkspace(QString)));
- connect(m_engine.data(), SIGNAL(fileChanged(QString)), this, SLOT(sendDocument(QString)));
- connect(m_engine.data(), SIGNAL(beginPublishWorkspace()), &m_publisher, SLOT(beginBulkSend()));
- connect(m_engine.data(), SIGNAL(endPublishWorkspace()), &m_publisher, SLOT(endBulkSend()));
- connect(&m_publisher, SIGNAL(needsPublishWorkspace()), this, SLOT(publishWorkspace()));
+ connect(m_engine.data(), &LiveHubEngine::workspaceChanged, &m_publisher, &RemotePublisher::setWorkspace);
+ connect(m_engine.data(), &LiveHubEngine::workspaceChanged, this, &HostWidget::refreshDocumentLabel);
+ connect(m_engine.data(), &LiveHubEngine::fileChanged, this, &HostWidget::sendDocument);
+ connect(m_engine.data(), &LiveHubEngine::beginPublishWorkspace, &m_publisher, &RemotePublisher::beginBulkSend);
+ connect(m_engine.data(), &LiveHubEngine::endPublishWorkspace, &m_publisher, &RemotePublisher::endBulkSend);
+ connect(&m_publisher, &RemotePublisher::needsPublishWorkspace, this, &HostWidget::publishWorkspace);
}
-void HostWidget::setCurrentFile(const QString currentFile)
+void HostWidget::setCurrentFile(const LiveDocument &currentFile)
{
- m_host->setCurrentFile(currentFile);
+ if (m_publisher.state() != QAbstractSocket::ConnectedState)
+ return;
+
+ m_publisher.activateDocument(currentFile);
}
bool HostWidget::followTreeSelection() const
@@ -164,70 +169,104 @@ bool HostWidget::followTreeSelection() const
return m_followTreeSelectionAction->isChecked();
}
-void HostWidget::updateName(const QString &name)
+void HostWidget::updateTitle()
{
- Q_UNUSED(name)
- if(m_host) {
- m_groupBox->setTitle(QString("%1 (%2:%3)").arg(m_host->name(), m_host->address(), QString::number(m_host->port())));
- }
+ m_groupBox->setTitle(QString("%1 (%2:%3)")
+ .arg(m_host->name())
+ .arg(m_host->address())
+ .arg(m_host->port()));
}
-void HostWidget::updateIp(const QString &ip)
+void HostWidget::updateFile(const LiveDocument &file)
{
- Q_UNUSED(ip)
- if(m_host) {
- m_groupBox->setTitle(QString("%1 (%2:%3)").arg(m_host->name(), m_host->address(), QString::number(m_host->port())));
+ QFont font(this->font());
+ QPalette palette(this->palette());
+ QString text;
+ QString toolTip;
+
+ if (file.isNull()) {
+ if (m_publisher.state() != QAbstractSocket::ConnectedState) {
+ text = tr("Host offline");
+ } else {
+ text = tr("No active document");
+ toolTip = tr("No active document. Drop one.");
+ }
+ font.setItalic(true);
+ } else {
+ text = file.relativeFilePath();
+
+ if (file.isFileIn(m_engine->workspace())) {
+ toolTip = file.absoluteFilePathIn(m_engine->workspace());
+ } else {
+ // red color from http://clrs.cc
+ palette.setColor(QPalette::Text, QColor(0xff, 0x41, 0x36));
+ toolTip = file.errorString();
+ }
}
- QTimer::singleShot(0, this, SLOT(connectToServer()));
-}
+ QFontMetrics metrics(font);
+ m_documentLabel->setFont(font);
+ m_documentLabel->setPalette(palette);
+ m_documentLabel->setText(metrics.elidedText(text, Qt::ElideLeft,
+ m_documentLabel->width()));
+ m_documentLabel->setToolTip(toolTip);
-void HostWidget::updatePort(int port)
-{
- Q_UNUSED(port)
- if(m_host) {
- m_groupBox->setTitle(QString("%1 (%2:%3)").arg(m_host->name(), m_host->address(), QString::number(m_host->port())));
+ if (m_host->followTreeSelection() && !file.isNull() && file != m_engine->activePath()) {
+ if (m_publisher.state() == QAbstractSocket::ConnectedState)
+ m_publisher.activateDocument(m_engine->activePath());
}
- QTimer::singleShot(0, this, SLOT(connectToServer()));
+ updateRemoteActions();
+}
+
+void HostWidget::refreshDocumentLabel()
+{
+ updateFile(m_host->currentFile());
}
-void HostWidget::updateFile(const QString &file)
+void HostWidget::updateAvailableState(bool available)
{
- QString relFile = QDir(m_engine->workspace()).relativeFilePath(file);
- setUpdateFile(relFile);
- m_documentLabel->setToolTip(relFile);
+ qCDebug(csLog) << "updateAvailableState()" << available;
- connectAndSendFile();
+ if (available)
+ scheduleConnectToServer();
+ else
+ onDisconnected();
}
-void HostWidget::setUpdateFile(const QString &file)
+void HostWidget::updateFollowTreeSelection(bool follow)
{
- QFontMetrics metrics(font());
- m_documentLabel->setText(metrics.elidedText(file, Qt::ElideLeft, m_documentLabel->width()));
+ m_followTreeSelectionAction->setChecked(follow);
+
+ if (follow && m_publisher.state() == QAbstractSocket::ConnectedState
+ && m_host->currentFile() != m_engine->activePath()) {
+ m_publisher.activateDocument(m_engine->activePath());
+ }
}
-void HostWidget::updateOnlineState(bool online)
+void HostWidget::updateRemoteActions()
{
- qDebug() << "updateOnline";
+ m_refreshAction->setEnabled(m_publisher.state() == QAbstractSocket::ConnectedState
+ && !m_host->currentFile().isNull());
+ m_publishAction->setEnabled(m_publisher.state() == QAbstractSocket::ConnectedState);
+}
- bool available = online || m_host->type() == Host::Manual;
+void HostWidget::scheduleConnectToServer()
+{
+ qCDebug(csLog) << "scheduleConnectToServer()" << m_host->name();
- if (available)
- QTimer::singleShot(0, this, SLOT(connectToServer()));
- else
- onDisconnected();
+ m_connectToServerTimer.start(0, this);
}
void HostWidget::connectToServer()
{
- qDebug() << "connectToServer";
+ qCDebug(csLog) << "connectToServer()" << m_host->name()
+ << m_publisher.state() << "available:" << m_host->available();
- if (m_publisher.state() == QAbstractSocket::ConnectedState || m_publisher.state() == QAbstractSocket::ConnectingState) {
+ if (m_publisher.state() != QAbstractSocket::UnconnectedState)
return;
- }
- if (m_host->online() || m_host->type() == Host::Manual) {
+ if (m_host->available()) {
m_publisher.connectToServer(m_host->address(), m_host->port());
m_activateId = QUuid();
m_rotationId = QUuid();
@@ -237,39 +276,45 @@ void HostWidget::connectToServer()
}
}
-void HostWidget::connectAndSendFile()
-{
- connectToServer();
- m_activateId = m_publisher.activateDocument(QDir(m_engine->workspace()).relativeFilePath(m_host->currentFile()));
-}
-
void HostWidget::onConnected()
{
+ qCDebug(csLog) << "Host connected:" << m_host->name();
+
m_connectDisconnectAction->setIcon(QIcon(":images/okay_ball.svg"));
m_connectDisconnectAction->setToolTip("Host online");
m_connectDisconnectAction->setText("Online");
+ updateFile(m_host->currentFile());
+ updateRemoteActions();
+
sendXOffset(m_host->xOffset());
sendYOffset(m_host->yOffset());
sendRotation(m_host->rotation());
- disconnect(m_connectDisconnectAction, SIGNAL(triggered()), 0, 0);
- connect(m_connectDisconnectAction, SIGNAL(triggered()), &m_publisher, SLOT(disconnectFromServer()));
+ disconnect(m_connectDisconnectAction, &QAction::triggered, 0, 0);
+ connect(m_connectDisconnectAction, &QAction::triggered, &m_publisher, &RemotePublisher::disconnectFromServer);
}
void HostWidget::onDisconnected()
{
+ qCDebug(csLog) << "Host disconnected:" << m_host->name();
+
m_connectDisconnectAction->setIcon(QIcon(":images/error_ball.svg"));
m_connectDisconnectAction->setToolTip("Host Offline");
m_connectDisconnectAction->setText("Offline");
resetProgressBar();
- disconnect(m_connectDisconnectAction, SIGNAL(triggered()), 0, 0);
- connect(m_connectDisconnectAction, SIGNAL(triggered()), this, SLOT(connectToServer()));
+ m_host->setCurrentFile(LiveDocument());
+ updateRemoteActions();
+
+ disconnect(m_connectDisconnectAction, &QAction::triggered, 0, 0);
+ connect(m_connectDisconnectAction, &QAction::triggered, this, &HostWidget::connectToServer);
}
void HostWidget::onConnectionError(QAbstractSocket::SocketError error)
{
+ qCDebug(csLog) << "Host connection error:" << m_host->name() << error;
+
m_connectDisconnectAction->setToolTip(m_publisher.errorToString(error));
m_connectDisconnectAction->setIcon(QIcon(":images/warning_ball.svg"));
@@ -282,7 +327,11 @@ void HostWidget::onConnectionError(QAbstractSocket::SocketError error)
void HostWidget::refresh()
{
- connectAndSendFile();
+ if (m_publisher.state() != QAbstractSocket::ConnectedState)
+ return;
+
+ if (!m_host->currentFile().isNull())
+ m_publisher.activateDocument(m_host->currentFile());
}
void HostWidget::probe()
@@ -292,13 +341,15 @@ void HostWidget::probe()
void HostWidget::publishWorkspace()
{
- connectToServer();
- connect(m_engine.data(), SIGNAL(publishFile(QString)), this, SLOT(sendDocument(QString)));
+ if (m_publisher.state() != QAbstractSocket::ConnectedState)
+ return;
+
+ connect(m_engine.data(), &LiveHubEngine::publishFile, this, &HostWidget::sendDocument);
m_engine->publishWorkspace();
- disconnect(m_engine.data(), SIGNAL(publishFile(QString)), this, SLOT(sendDocument(QString)));
+ disconnect(m_engine.data(), &LiveHubEngine::publishFile, this, &HostWidget::sendDocument);
}
-void HostWidget::sendDocument(const QString& document)
+void HostWidget::sendDocument(const LiveDocument& document)
{
if (m_publisher.state() != QAbstractSocket::ConnectedState)
return;
@@ -407,7 +458,7 @@ void HostWidget::resizeEvent(QResizeEvent *event)
{
Q_UNUSED(event);
- setUpdateFile(m_documentLabel->toolTip());
+ refreshDocumentLabel();
}
void HostWidget::showPinDialog()
@@ -423,19 +474,33 @@ void HostWidget::showPinDialog()
void HostWidget::dragEnterEvent(QDragEnterEvent *event)
{
- if (event->mimeData()->hasFormat("text/uri-list") && (m_host->online() || m_host->type() == Host::Manual)) {
+ if (m_publisher.state() != QAbstractSocket::ConnectedState)
+ return;
+ if (event->mimeData()->hasUrls())
event->acceptProposedAction();
- }
}
void HostWidget::dropEvent(QDropEvent *event)
{
- QUrl url(event->mimeData()->text());
+ if (m_publisher.state() != QAbstractSocket::ConnectedState)
+ return;
- if (url.isLocalFile())
- m_host->setCurrentFile(url.toLocalFile());
event->acceptProposedAction();
+
+ QUrl url(event->mimeData()->urls().first());
+ if (url.isLocalFile()) {
+ LiveDocument document = LiveDocument::resolve(m_engine->workspace(), url.toLocalFile());
+ if (!document.isNull() && document.isFileIn(m_engine->workspace())) {
+ if (m_host->followTreeSelection() && document != m_engine->activePath())
+ m_host->setFollowTreeSelection(false);
+ m_publisher.activateDocument(document);
+ } else {
+ QMessageBox::warning(this, tr("Not a workspace document"),
+ tr("The dropped document is not a file in the current workspace:<br/>%1")
+ .arg(url.toString()));
+ }
+ }
}
bool HostWidget::eventFilter(QObject *object, QEvent *event)
@@ -449,3 +514,11 @@ bool HostWidget::eventFilter(QObject *object, QEvent *event)
return false;
}
+
+void HostWidget::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == m_connectToServerTimer.timerId()) {
+ m_connectToServerTimer.stop();
+ connectToServer();
+ }
+}
diff --git a/src/bench/hostwidget.h b/src/bench/hostwidget.h
index 42188e7..7bb3366 100644
--- a/src/bench/hostwidget.h
+++ b/src/bench/hostwidget.h
@@ -35,6 +35,7 @@
#include <remotepublisher.h>
class Host;
+class LiveDocument;
class HostWidget : public QWidget
{
@@ -45,7 +46,7 @@ public:
void setHost(Host* host);
void setLiveHubEngine(LiveHubEngine* engine);
- void setCurrentFile(const QString currentFile);
+ void setCurrentFile(const LiveDocument &currentFile);
bool followTreeSelection() const;
signals:
@@ -63,23 +64,24 @@ protected:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
bool eventFilter(QObject *, QEvent *);
+ void timerEvent(QTimerEvent *event);
private slots:
- void updateName(const QString& name);
- void updateIp(const QString& ip);
- void updatePort(int port);
- void updateFile(const QString& file);
- void setUpdateFile(const QString& file);
- void updateOnlineState(bool online);
-
+ void updateTitle();
+ void updateFile(const LiveDocument& file);
+ void refreshDocumentLabel();
+ void updateAvailableState(bool available);
+ void updateFollowTreeSelection(bool follow);
+ void updateRemoteActions();
+
+ void scheduleConnectToServer();
void connectToServer();
- void connectAndSendFile();
void onConnected();
void onDisconnected();
void onConnectionError(QAbstractSocket::SocketError error);
- void sendDocument(const QString &document);
+ void sendDocument(const LiveDocument &document);
void sendXOffset(int offset);
void sendYOffset(int offset);
@@ -116,6 +118,7 @@ private:
RemotePublisher m_publisher;
QPointer<LiveHubEngine> m_engine;
+ QBasicTimer m_connectToServerTimer;
QUuid m_activateId;
QList<QUuid> m_changeIds;
diff --git a/src/bench/importpathoptionpage.cpp b/src/bench/importpathoptionpage.cpp
index 151e919..34fd3e1 100644
--- a/src/bench/importpathoptionpage.cpp
+++ b/src/bench/importpathoptionpage.cpp
@@ -48,9 +48,9 @@ ImportPathOptionPage::ImportPathOptionPage(QWidget *parent) :
}
s.endArray();
- connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addItem()));
- connect(ui->removeButton, SIGNAL(clicked()), this, SLOT(removeItem()));
- connect(ui->editButton, SIGNAL(clicked()), this, SLOT(editItem()));
+ connect(ui->addButton, &QAbstractButton::clicked, this, &ImportPathOptionPage::addItem);
+ connect(ui->removeButton, &QAbstractButton::clicked, this, &ImportPathOptionPage::removeItem);
+ connect(ui->editButton, &QAbstractButton::clicked, this, &ImportPathOptionPage::editItem);
}
ImportPathOptionPage::~ImportPathOptionPage()
diff --git a/src/bench/main.cpp b/src/bench/main.cpp
index 62b8bb3..9c8b519 100644
--- a/src/bench/main.cpp
+++ b/src/bench/main.cpp
@@ -29,6 +29,8 @@
**
****************************************************************************/
+#include <functional>
+
#include <QtGui>
#include <QtWidgets>
@@ -166,6 +168,7 @@ void Application::setDarkStyle()
palette.setColor(QPalette::Text, QColor("#F0F0F0"));
palette.setColor(QPalette::Button, QColor("#353535"));
palette.setColor(QPalette::ButtonText, QColor("#FFFFFF"));
+ palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor("#A0A0A0"));
palette.setColor(QPalette::BrightText, QColor("#D0021B"));
palette.setColor(QPalette::Highlight, QColor("#F19300"));
palette.setColor(QPalette::HighlightedText, QColor("#1C1C1C"));
@@ -181,9 +184,9 @@ void Application::parseArguments(const QStringList &arguments, Options *options)
parser.addPositionalArgument("workspace", "workspace folder to watch. If this points to a QML document, than the directory is asssumed to be the workspace and the file the active document.");
parser.addPositionalArgument("document", "main QML document to load initially.");
- QCommandLineOption pluginPathOption("pluginpath", "path to qmllive plugins", "pluginpath");
+ QCommandLineOption pluginPathOption("pluginpath", "path to QmlLive plugins", "pluginpath");
parser.addOption(pluginPathOption);
- QCommandLineOption importPathOption("importpath", "path to qml import path. Can appear multiple times", "importpath");
+ QCommandLineOption importPathOption("importpath", "path to QML import path. Can appear multiple times", "importpath");
parser.addOption(importPathOption);
QCommandLineOption stayOnTopOption("stayontop", "keep viewer window on top");
parser.addOption(stayOnTopOption);
@@ -271,7 +274,7 @@ void Application::parseArguments(const QStringList &arguments, Options *options)
parser.showHelp(-1);
}
options->setWorkspace(fi.absolutePath());
- options->setActiveDocument(fi.absoluteFilePath());
+ options->setActiveDocument(LiveDocument(fi.absoluteFilePath()));
} else {
qDebug() << "First argument does not ending with \".qml\". Assuming it is a workspace.";
if (!fi.exists() || !fi.isDir()) {
@@ -286,11 +289,12 @@ void Application::parseArguments(const QStringList &arguments, Options *options)
QFileInfo fi(argument);
if (argument.endsWith(".qml")) {
qDebug() << "Second argument ends with \".qml\". Assuming it is a file.";
- if (!fi.exists() || !fi.isFile()) {
- qWarning() << "Document does not exist or is not a file: " << fi.absoluteFilePath();
+ LiveDocument document = LiveDocument::resolve(options->workspace(), argument);
+ if (document.isNull() || !document.isFileIn(options->workspace())) {
+ qWarning() << document.errorString();
parser.showHelp(-1);
}
- options->setActiveDocument(fi.absoluteFilePath());
+ options->setActiveDocument(document);
} else {
qWarning() << "If second argument is present it needs to be a QML document: " << fi.absoluteFilePath();
parser.showHelp(-1);
@@ -381,7 +385,7 @@ void MasterApplication::listenForArguments()
void MasterApplication::applyOptions(const Options &options)
{
if (!options.workspace().isEmpty())
- m_window->setWorkspace(QDir(options.workspace()).absolutePath());
+ m_window->setWorkspace(QDir(options.workspace()).absolutePath(), false);
if (!options.pluginPath().isEmpty()) {
if (!m_window->isInitialized())
@@ -397,7 +401,7 @@ void MasterApplication::applyOptions(const Options &options)
qDebug() << "Ignoring attempt to set import paths after initialization.";
}
- if (!options.activeDocument().isEmpty()) {
+ if (!options.activeDocument().isNull()) {
m_window->activateDocument(options.activeDocument());
}
diff --git a/src/bench/mainwindow.cpp b/src/bench/mainwindow.cpp
index ac418c9..61924aa 100644
--- a/src/bench/mainwindow.cpp
+++ b/src/bench/mainwindow.cpp
@@ -77,17 +77,17 @@ MainWindow::MainWindow(QWidget *parent)
m_hub->setFilePublishingActive(true);
m_node->setWorkspaceView(m_workspace);
- connect(m_workspace, SIGNAL(pathActivated(QString)), m_hub, SLOT(setActivePath(QString)));
- connect(m_workspace, SIGNAL(pathActivated(QString)), m_hostManager, SLOT(followTreeSelection(QString)));
- connect(m_hub, SIGNAL(activateDocument(QString)), this, SLOT(updateWindowTitle()));
- connect(m_hub, SIGNAL(activateDocument(QString)), m_node, SLOT(setActiveDocument(QString)));
- connect(m_node, SIGNAL(activeWindowChanged(QQuickWindow*)), this, SLOT(onActiveWindowChanged(QQuickWindow*)));
- connect(m_node->qmlEngine(), SIGNAL(quit()), this, SLOT(logQuitEvent()));
- connect(m_allHosts, SIGNAL(publishAll()), m_hostManager, SLOT(publishAll()));
- connect(m_allHosts, SIGNAL(currentFileChanged(QString)), m_hostManager, SLOT(setCurrentFile(QString)));
- connect(m_allHosts, SIGNAL(refreshAll()), m_hostManager, SLOT(refreshAll()));
- connect(m_hostManager, SIGNAL(logWidgetAdded(QDockWidget*)), this, SLOT(onLogWidgetAdded(QDockWidget*)));
- connect(m_hostManager, SIGNAL(openHostConfig(Host*)), this, SLOT(openPreferences(Host*)));
+ connect(m_workspace, &WorkspaceView::pathActivated, m_hub, &LiveHubEngine::setActivePath);
+ connect(m_workspace, &WorkspaceView::pathActivated, m_hostManager, &HostManager::followTreeSelection);
+ connect(m_hub, &LiveHubEngine::activateDocument, this, &MainWindow::updateWindowTitle);
+ connect(m_hub, &LiveHubEngine::activateDocument, m_node, &LiveNodeEngine::loadDocument);
+ connect(m_node, &LiveNodeEngine::activeWindowChanged, this, &MainWindow::onActiveWindowChanged);
+ connect(m_node->qmlEngine(), &QQmlEngine::quit, this, &MainWindow::logQuitEvent);
+ connect(m_allHosts, &AllHostsWidget::publishAll, m_hostManager, &HostManager::publishAll);
+ connect(m_allHosts, &AllHostsWidget::currentFileChanged, m_hostManager, &HostManager::setCurrentFile);
+ connect(m_allHosts, &AllHostsWidget::refreshAll, m_hostManager, &HostManager::refreshAll);
+ connect(m_hostManager, &HostManager::logWidgetAdded, this, &MainWindow::onLogWidgetAdded);
+ connect(m_hostManager, &HostManager::openHostConfig, this, &MainWindow::openPreferences);
m_qmlDefaultimportList = m_node->qmlEngine()->importPathList();
}
@@ -168,34 +168,78 @@ void MainWindow::setupLogView()
m_logDock->setFeatures(QDockWidget::AllDockWidgetFeatures);
addDockWidget(Qt::BottomDockWidgetArea, m_logDock);
- connect(m_node, SIGNAL(clearLog()), m_log, SLOT(clear()));
- connect(m_node, SIGNAL(logIgnoreMessages(bool)), m_log, SLOT(setIgnoreMessages(bool)));
- connect(m_node, SIGNAL(logErrors(QList<QQmlError>)), m_log, SLOT(appendToLog(QList<QQmlError>)));
+ connect(m_node, &LiveNodeEngine::clearLog, m_log, &LogView::clear);
+ connect(m_node, &LiveNodeEngine::logIgnoreMessages, m_log, &LogView::setIgnoreMessages);
+ connect(m_node, &LiveNodeEngine::logErrors, m_log, &LogView::appendAllToLog);
}
void MainWindow::setupMenuBar()
{
QMenu *file = menuBar()->addMenu(tr("&File"));
+#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
m_openWorkspace = file->addAction(QIcon::fromTheme("folder-open"), tr("&Open Workspace..."), this, SLOT(openWorkspace()), QKeySequence::Open);
+#else
+ m_openWorkspace = file->addAction(QIcon::fromTheme("folder-open"), tr("&Open Workspace..."),
+ this, &MainWindow::openWorkspace, QKeySequence::Open);
+#endif
m_recentMenu = file->addMenu(QIcon::fromTheme("document-open-recent"), "&Recent");
m_recentMenu->setEnabled(false);
+#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
file->addAction(tr("Preferences..."), this, SLOT(openPreferences()), QKeySequence::Preferences);
+#else
+ file->addAction(tr("Preferences..."), this, [this] { openPreferences(); },
+ QKeySequence::Preferences);
+#endif
file->addSeparator();
+#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
file->addAction(QIcon::fromTheme("application-exit"), tr("&Quit"), this, SLOT(close()), QKeySequence::Quit);
+#else
+ file->addAction(QIcon::fromTheme("application-exit"), tr("&Quit"),
+ this, &MainWindow::close, QKeySequence::Quit);
+#endif
QMenu *view = menuBar()->addMenu(tr("&View"));
+#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
view->addAction(tr("Take Snapshot"), this, SLOT(takeSnapshot()), QKeySequence("Ctrl+F3"));
+#else
+ view->addAction(tr("Take Snapshot"), this, &MainWindow::takeSnapshot, QKeySequence("Ctrl+F3"));
+#endif
view->addSeparator();
+#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
QAction *slow = view->addAction(tr("Slow Down Animations"), this, SLOT(slowDownAnimations(bool)), QKeySequence(tr("Ctrl+.")));
+#else
+ QAction *slow = view->addAction(tr("Slow Down Animations"),
+ this, &MainWindow::slowDownAnimations,
+ QKeySequence(tr("Ctrl+.")));
+#endif
slow->setCheckable(true);
view->addSeparator();
+#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
m_refresh = view->addAction(QIcon::fromTheme("view-refresh"), tr("Refresh"), m_node, SLOT(refresh()), QKeySequence::Refresh);
+#else
+ m_refresh = view->addAction(QIcon::fromTheme("view-refresh"), tr("Refresh"),
+ m_node, &BenchLiveNodeEngine::refresh, QKeySequence::Refresh);
+#endif
+#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
m_resizeFit = view->addAction(QIcon::fromTheme("zoom-fit-best"), tr("Resize to Fit"), this, SLOT(resizeToFit()));
+#else
+ m_resizeFit = view->addAction(QIcon::fromTheme("zoom-fit-best"), tr("Resize to Fit"),
+ this, &MainWindow::resizeToFit);
+#endif
+#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
view->addAction(tr("Show Containing Folder"), m_workspace, SLOT(goUp()), QKeySequence("Ctrl+Esc"));
+#else
+ view->addAction(tr("Show Containing Folder"), m_workspace, &WorkspaceView::goUp,
+ QKeySequence("Ctrl+Esc"));
+#endif
+#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
m_stayOnTop = view->addAction(tr("Stay on Top"), this, SLOT(stayOnTop()));
+#else
+ m_stayOnTop = view->addAction(tr("Stay on Top"), this, &MainWindow::stayOnTop);
+#endif
m_stayOnTop->setCheckable(true);
view->addSeparator();
@@ -205,7 +249,7 @@ void MainWindow::setupMenuBar()
m_logDockMenu->addAction(m_logDock->toggleViewAction());
QMenu *help = menuBar()->addMenu(tr("&Help"));
- QAction *about = help->addAction(tr("About Qt QML Live..."));
+ QAction *about = help->addAction(tr("About Qt QmlLive..."));
connect(about, &QAction::triggered, this, [this]() { AboutDialog::exec(this); });
about->setMenuRole(QAction::AboutRole);
}
@@ -216,7 +260,7 @@ void MainWindow::init()
restoreGeometry(s.value("geometry").toByteArray());
//Only set the workspace if we didn't already set it by command line
if (m_workspacePath.isEmpty()) {
- setWorkspace(s.value("workspace", QDir::currentPath()).toString());
+ setWorkspace(s.value("workspace", QDir::currentPath()).toString(), false);
}
if (s.value("http_proxy/enabled").toBool()) {
@@ -240,13 +284,15 @@ void MainWindow::init()
updateRecentFolder();
- //Only set the workspace if we didn't already set it by command line
- if (m_node->activeDocument().isEmpty()) {
- if (s.contains("activeDocument")) {
- activateDocument(s.value("activeDocument").toString());
- } else {
+ //Only set the document if we didn't already set it by command line
+ if (m_node->activeDocument().isNull()) {
+ LiveDocument last;
+ if (s.contains("activeDocument"))
+ last = LiveDocument::resolve(m_workspacePath, s.value("activeDocument").toString());
+ if (!last.isNull())
+ activateDocument(last);
+ else
m_workspace->activateRootPath();
- }
}
resetImportPaths();
@@ -263,7 +309,8 @@ void MainWindow::writeSettings()
s.setValue("geometry", saveGeometry());
s.setValue("windowState", saveState());
s.setValue("workspace", m_workspacePath);
- s.setValue("activeDocument", m_node->activeDocument().toLocalFile());
+ if (!m_node->activeDocument().isNull())
+ s.setValue("activeDocument", m_node->activeDocument().relativeFilePath());
s.beginWriteArray("recentFolder");
for (int i = 0; i < m_recentFolder.count(); i++) {
@@ -300,7 +347,7 @@ void MainWindow::setupToolBar()
m_toolBar->addAction(m_resizeFit);
}
-void MainWindow::activateDocument(const QString path)
+void MainWindow::activateDocument(const LiveDocument &path)
{
m_workspace->activateDocument(path);
}
@@ -338,13 +385,15 @@ void MainWindow::slowDownAnimations(bool enable)
}
-void MainWindow::setWorkspace(const QString& path)
+void MainWindow::setWorkspace(const QString& path, bool activateRootPath)
{
m_workspacePath = path;
m_workspace->setRootPath(path);
m_node->setWorkspace(path);
m_hub->setWorkspace(path);
m_allHosts->setWorkspace(path);
+ if (activateRootPath)
+ m_workspace->activateRootPath();
updateRecentFolder(path);
}
@@ -393,11 +442,11 @@ void MainWindow::logQuitEvent()
void MainWindow::updateWindowTitle()
{
setWindowFilePath(QString());
- if (m_hub->activePath().isEmpty()) {
+ if (m_hub->activePath().isNull()) {
setWindowTitle(QApplication::applicationName());
} else {
setWindowTitle(QString());
- setWindowFilePath(m_hub->activePath());
+ setWindowFilePath(m_hub->activePath().absoluteFilePathIn(m_workspacePath));
}
}
@@ -443,11 +492,19 @@ void MainWindow::updateRecentFolder(const QString& path)
m_recentMenu->clear();
foreach (const QString file, m_recentFolder) {
+#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
m_recentMenu->addAction(file, this, SLOT(openRecentFolder()));
+#else
+ m_recentMenu->addAction(file, this, &MainWindow::openRecentFolder);
+#endif
}
m_recentMenu->addSeparator();
+#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
m_recentMenu->addAction("Clear Menu", this, SLOT(clearRecentFolder()));
+#else
+ m_recentMenu->addAction("Clear Menu", this, &MainWindow::clearRecentFolder);
+#endif
}
void MainWindow::stayOnTop()
diff --git a/src/bench/mainwindow.h b/src/bench/mainwindow.h
index f410121..4a7e8f1 100644
--- a/src/bench/mainwindow.h
+++ b/src/bench/mainwindow.h
@@ -39,6 +39,7 @@
class BenchQuickView;
class WorkspaceView;
class LogView;
+class LiveDocument;
class LiveRuntime;
class LiveHubEngine;
class BenchLiveNodeEngine;
@@ -57,8 +58,8 @@ class MainWindow : public QMainWindow
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
- void activateDocument(const QString path);
- void setWorkspace(const QString& path);
+ void activateDocument(const LiveDocument &path);
+ void setWorkspace(const QString& path, bool activateRootPath = true);
void setPluginPath(const QString& path);
void setImportPaths(const QStringList& pathList);
void setStaysOnTop(bool enabled);
diff --git a/src/bench/options.cpp b/src/bench/options.cpp
index 7fa8386..5baedc2 100644
--- a/src/bench/options.cpp
+++ b/src/bench/options.cpp
@@ -85,12 +85,12 @@ void Options::setPing(bool ping)
m_ping = ping;
}
-QString Options::activeDocument() const
+LiveDocument Options::activeDocument() const
{
return m_activeDocument;
}
-void Options::setActiveDocument(const QString &activeDocument)
+void Options::setActiveDocument(const LiveDocument &activeDocument)
{
m_activeDocument = activeDocument;
}
diff --git a/src/bench/options.h b/src/bench/options.h
index 2760059..e7c84bd 100644
--- a/src/bench/options.h
+++ b/src/bench/options.h
@@ -31,6 +31,8 @@
#pragma once
+#include "livedocument.h"
+
#include <QtCore>
class Options : public QObject
@@ -58,8 +60,8 @@ public:
bool ping() const;
void setPing(bool ping);
- QString activeDocument() const;
- void setActiveDocument(const QString &activeDocument);
+ LiveDocument activeDocument() const;
+ void setActiveDocument(const LiveDocument &activeDocument);
QString workspace() const;
void setWorkspace(const QString &workspace);
@@ -88,7 +90,7 @@ private:
bool m_noRemote;
bool m_remoteOnly;
bool m_ping;
- QString m_activeDocument;
+ LiveDocument m_activeDocument;
QString m_workspace;
QString m_pluginPath;
QStringList m_importPaths;
diff --git a/src/bench/optionsdialog.cpp b/src/bench/optionsdialog.cpp
index ef99807..00c5898 100644
--- a/src/bench/optionsdialog.cpp
+++ b/src/bench/optionsdialog.cpp
@@ -60,8 +60,8 @@ OptionsDialog::OptionsDialog(QWidget *parent)
item->setData(Qt::UserRole, index);
ui->optionsView->addItem(item);
- connect(ui->optionsView, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
- this, SLOT(optionSelected(QListWidgetItem*)));
+ connect(ui->optionsView, &QListWidget::currentItemChanged,
+ this, &OptionsDialog::optionSelected);
}
OptionsDialog::~OptionsDialog()
diff --git a/src/ipc/ipcclient.cpp b/src/ipc/ipcclient.cpp
index 50ef363..ada2511 100644
--- a/src/ipc/ipcclient.cpp
+++ b/src/ipc/ipcclient.cpp
@@ -84,13 +84,14 @@ IpcClient::IpcClient(QObject *parent)
, m_written(0)
, m_connection(new IpcConnection(m_socket))
{
- connect(m_socket, SIGNAL(connected()), this, SIGNAL(connected()));
- connect(m_socket, SIGNAL(connected()), this, SLOT(processQueue()));
- connect(m_socket, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
- connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
- connect(m_socket, SIGNAL(bytesWritten(qint64)), this , SLOT(onBytesWritten(qint64)));
-
- connect(m_connection, SIGNAL(received(QString,QByteArray)), this, SIGNAL(received(QString,QByteArray)));
+ connect(m_socket, &QAbstractSocket::connected, this, &IpcClient::connected);
+ connect(m_socket, &QAbstractSocket::connected, this, &IpcClient::processQueue);
+ connect(m_socket, &QAbstractSocket::disconnected, this, &IpcClient::disconnected);
+ void (QAbstractSocket::*QAbstractSocket__error)(QAbstractSocket::SocketError) = &QAbstractSocket::error;
+ connect(m_socket, QAbstractSocket__error, this, &IpcClient::onError);
+ connect(m_socket, &QAbstractSocket::bytesWritten, this, &IpcClient::onBytesWritten);
+
+ connect(m_connection, &IpcConnection::received, this, &IpcClient::received);
}
IpcClient::IpcClient(QTcpSocket *socket, QObject *parent)
@@ -100,10 +101,11 @@ IpcClient::IpcClient(QTcpSocket *socket, QObject *parent)
, m_written(0)
, m_connection(0)
{
- connect(m_socket, SIGNAL(connected()), this, SIGNAL(connected()));
- connect(m_socket, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
- connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
- connect(m_socket, SIGNAL(bytesWritten(qint64)), this , SLOT(onBytesWritten(qint64)));
+ connect(m_socket, &QAbstractSocket::connected, this, &IpcClient::connected);
+ connect(m_socket, &QAbstractSocket::disconnected, this, &IpcClient::disconnected);
+ void (QAbstractSocket::*QAbstractSocket__error)(QAbstractSocket::SocketError) = &QAbstractSocket::error;
+ connect(m_socket, QAbstractSocket__error, this, &IpcClient::onError);
+ connect(m_socket, &QAbstractSocket::bytesWritten, this, &IpcClient::onBytesWritten);
}
/*!
@@ -115,7 +117,7 @@ QAbstractSocket::SocketState IpcClient::state() const
}
/*!
- * Sets the Ip-Address to \a hostName and port to \a port to be used for a ipc call.
+ * Sets the Ip-Address to \a hostName and port to \a port to be used for a IPC call.
*/
void IpcClient::connectToServer(const QString &hostName, int port)
{
@@ -140,7 +142,11 @@ QUuid IpcClient::send(const QString &method, const QByteArray &data)
pkg->m_tries = 0;
m_queue.enqueue(pkg);
+#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0)
QTimer::singleShot(0, this, SLOT(processQueue()));
+#else
+ QTimer::singleShot(0, this, &IpcClient::processQueue);
+#endif
return pkg->m_uuid;
}
@@ -295,7 +301,11 @@ void IpcClient::processQueue()
DEBUG << "Tried to sent the package" << m_current->m_tries << "times, but didn't succeed";
m_queue.dequeue();
onError(QAbstractSocket::ConnectionRefusedError);
+#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0)
QTimer::singleShot(0, this, SLOT(processQueue()));
+#else
+ QTimer::singleShot(0, this, &IpcClient::processQueue);
+#endif
return;
}
@@ -305,7 +315,11 @@ void IpcClient::processQueue()
m_queue.dequeue();
m_current->m_bytes = size;
} else {
+#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0)
QTimer::singleShot(1000, this, SLOT(processQueue()));
+#else
+ QTimer::singleShot(1000, this, &IpcClient::processQueue);
+#endif
m_current = 0;
}
}
@@ -335,7 +349,11 @@ void IpcClient::onError(QAbstractSocket::SocketError socketError)
delete m_current;
m_current = 0;
+#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0)
QTimer::singleShot(0, this, SLOT(processQueue()));
+#else
+ QTimer::singleShot(0, this, &IpcClient::processQueue);
+#endif
}
if ((m_socket->state() != QAbstractSocket::ConnectedState &&
diff --git a/src/ipc/ipcconnection.cpp b/src/ipc/ipcconnection.cpp
index 8d35e07..32c038e 100644
--- a/src/ipc/ipcconnection.cpp
+++ b/src/ipc/ipcconnection.cpp
@@ -54,9 +54,10 @@ IpcConnection::IpcConnection(QTcpSocket *socket, QObject *parent)
{
DEBUG << "IpcConnection()";
- connect(m_socket, SIGNAL(disconnected()), this, SLOT(close()));
- connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(closeWithError()));
- connect(m_socket, SIGNAL(readyRead()), this, SLOT(readData()));
+ connect(m_socket, &QAbstractSocket::disconnected, this, &IpcConnection::close);
+ void (QAbstractSocket::*QAbstractSocket__error)(QAbstractSocket::SocketError) = &QAbstractSocket::error;
+ connect(m_socket, QAbstractSocket__error, this, &IpcConnection::closeWithError);
+ connect(m_socket, &QAbstractSocket::readyRead, this, &IpcConnection::readData);
}
/**
diff --git a/src/ipc/ipcserver.cpp b/src/ipc/ipcserver.cpp
index f23aaa6..3d8288c 100644
--- a/src/ipc/ipcserver.cpp
+++ b/src/ipc/ipcserver.cpp
@@ -49,10 +49,7 @@
*
* \code{.cpp}
* m_server = new IpcServer(this);
- * connect(
- * m_server, SIGNAL(received(QString,QByteArray)),
- * this, SLOT(handleCall(QString, QByteArray))
- * );
+ * connect(m_server, &IpcServer::received, this, &MyHandler::handleCall);
* m_server->listen(10234);
*
* ...
@@ -75,7 +72,7 @@ IpcServer::IpcServer(QObject *parent)
: QObject(parent)
, m_server(new QTcpServer(this))
{
- connect(m_server, SIGNAL(newConnection()), this, SLOT(newConnection()));
+ connect(m_server, &QTcpServer::newConnection, this, &IpcServer::newConnection);
}
/*!
@@ -98,8 +95,8 @@ void IpcServer::newConnection()
emit clientConnected(socket->peerAddress());
emit clientConnected(socket);
IpcConnection *connection = new IpcConnection(socket, this);
- connect(connection, SIGNAL(connectionClosed()), this, SLOT(onConnectionClosed()));
- connect(connection, SIGNAL(received(QString,QByteArray)), this, SIGNAL(received(QString,QByteArray)));
+ connect(connection, &IpcConnection::connectionClosed, this, &IpcServer::onConnectionClosed);
+ connect(connection, &IpcConnection::received, this, &IpcServer::received);
}
}
@@ -126,9 +123,9 @@ void IpcServer::setMaxConnections(int num)
/*!
* \fn void IpcServer::received(const QString& method, const QByteArray& content)
- * \brief signals a ipc call has arrived
+ * \brief signals a IPC call has arrived
*
- * A ipc call requesting \a method and using \a content a the parameters for the method
+ * A IPC call requesting \a method and using \a content a the parameters for the method
*/
/*!
diff --git a/src/lib.pro b/src/lib.pro
index 89baf59..b5f8ab6 100755
--- a/src/lib.pro
+++ b/src/lib.pro
@@ -28,7 +28,7 @@ INSTALLS += headers
!win32 {
CONFIG += create_pc create_prl no_install_prl
QMAKE_PKGCONFIG_NAME = qmllive
- QMAKE_PKGCONFIG_DESCRIPTION = Qt QML Live Library
+ QMAKE_PKGCONFIG_DESCRIPTION = Qt QmlLive Library
QMAKE_PKGCONFIG_PREFIX = $$PREFIX
QMAKE_PKGCONFIG_LIBDIR = ${prefix}/lib
QMAKE_PKGCONFIG_INCDIR = ${prefix}/include/qmllive
diff --git a/src/livedocument.cpp b/src/livedocument.cpp
new file mode 100644
index 0000000..d4347cf
--- /dev/null
+++ b/src/livedocument.cpp
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#include "livedocument.h"
+
+#include <QDebug>
+
+/*!
+ * \class LiveDocument
+ * \brief Encapsulates a relative path to a workspace document
+ * \inmodule qmllive
+ */
+
+/*!
+ * Constructs a null instance.
+ *
+ * \sa isNull(), errorString()
+ */
+LiveDocument::LiveDocument()
+{
+ m_errorString = tr("Internal error: A null LiveDocument passed");
+}
+
+/*!
+ * Constructs instance for the given \a relativeFilePath.
+ *
+ * The \a relativeFilePath MUST NOT be an empty string, it MUST be a relative
+ * path, and when resolved relatively to a directory it MUST NOT resolve to a
+ * path outside of the directory.
+ */
+LiveDocument::LiveDocument(const QString &relativeFilePath)
+{
+ LIVE_ASSERT(!relativeFilePath.isEmpty(), return);
+ LIVE_ASSERT(QDir::isRelativePath(relativeFilePath), return);
+ LIVE_ASSERT(!QDir::cleanPath(relativeFilePath).startsWith(QLatin1String("../")), return);
+
+ m_relativeFilePath = relativeFilePath;
+}
+
+/*!
+ * \fn bool LiveDocument::isNull() const
+ *
+ * Returns true if this is a null instance.
+ *
+ * A null instance has been either contructed with the default constructor or
+ * the resolve() call failed.
+ *
+ * \sa errorString()
+ */
+
+/*!
+ * \fn QString LiveDocument::errorString() const
+ *
+ * When called just after resolve(), existsIn() or isFileIn() failed, returns a
+ * descriptive message suitable for displaying in user interface. When called in
+ * other context, the result is undefined.
+ */
+
+/*!
+ * Returns \c true if this document exists in the given \a workspace directory.
+ *
+ * \sa errorString()
+ */
+bool LiveDocument::existsIn(const QDir &workspace) const
+{
+ LIVE_ASSERT(!isNull(), return false);
+
+ bool exists = QFileInfo(workspace, m_relativeFilePath).exists();
+ if (!exists) {
+ m_errorString = tr("Document '%1' does not exist in workspace '%2'")
+ .arg(m_relativeFilePath)
+ .arg(workspace.path());
+ }
+ return exists;
+}
+
+/*!
+ * Returns \c true if this document exists as a regular file (or a symbolic link
+ * to a regular file) in the given \a workspace directory.
+ *
+ * Symbolic links resolution applies.
+ *
+ * \sa errorString()
+ */
+bool LiveDocument::isFileIn(const QDir &workspace) const
+{
+ LIVE_ASSERT(!isNull(), return false);
+
+ if (!existsIn(workspace))
+ return false;
+
+ bool isFile = QFileInfo(workspace, m_relativeFilePath).isFile();
+ if (!isFile) {
+ m_errorString = tr("Document '%1' is a non-regular file in workspace '%2'")
+ .arg(m_relativeFilePath)
+ .arg(workspace.path());
+ }
+ return isFile;
+}
+
+/*!
+ * Returns the relative file path including the file name.
+ */
+QString LiveDocument::relativeFilePath() const
+{
+ LIVE_ASSERT(!isNull(), return QString());
+
+ return m_relativeFilePath;
+}
+
+/*!
+ * Returns the absolute file path within a \a workspace, including the file name.
+ */
+QString LiveDocument::absoluteFilePathIn(const QDir &workspace) const
+{
+ LIVE_ASSERT(!isNull(), return QString());
+
+ return QDir::cleanPath(workspace.absoluteFilePath(m_relativeFilePath));
+}
+
+/*!
+ * Constructs a non-null instance unless the \a filePath resolves outside of the
+ * \a workspace directory.
+ *
+ * \a filePath may be an absolute or relative file path to a file which is NOT
+ * required to exist.
+ *
+ * \sa isNull(), errorString()
+ */
+LiveDocument LiveDocument::resolve(const QDir &workspace, const QString &filePath)
+{
+ LiveDocument retv;
+
+ if (filePath.isEmpty()) {
+ qWarning() << "filePath is an empty string";
+ retv.m_errorString = tr("Not a valid file path: ''");
+ return retv;
+ }
+
+ QString relativeFilePath = workspace.relativeFilePath(filePath);
+ QString cleanPath = QDir::cleanPath(relativeFilePath);
+ if (cleanPath.isEmpty()) {
+ retv.m_relativeFilePath = QStringLiteral(".");
+ } else if (!cleanPath.startsWith(QLatin1String("../"))) {
+ retv.m_relativeFilePath = relativeFilePath;
+ } else {
+ retv.m_errorString = tr("Document path '%1' is outside the workspace directory '%2'")
+ .arg(filePath).arg(workspace.path());
+ }
+
+ return retv;
+}
+
+/*!
+ * Allows to print LiveDocument \a document via debug stream \a dbg.
+ */
+QDebug operator<<(QDebug dbg, const LiveDocument &document)
+{
+ if (document.isNull())
+ dbg << QStringLiteral("<null>");
+ else
+ dbg << document.relativeFilePath();
+
+ return dbg;
+}
diff --git a/src/livedocument.h b/src/livedocument.h
new file mode 100644
index 0000000..6aa9b0c
--- /dev/null
+++ b/src/livedocument.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QmlLive tool.
+**
+** $QT_BEGIN_LICENSE:GPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: GPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtCore>
+
+#include "qmllive_global.h"
+
+class QMLLIVESHARED_EXPORT LiveDocument
+{
+ Q_DECLARE_TR_FUNCTIONS(LiveDocument)
+
+public:
+ LiveDocument();
+ explicit LiveDocument(const QString &relativeFilePath);
+
+ bool isNull() const { return m_relativeFilePath.isEmpty(); }
+ QString errorString() const { return m_errorString; }
+
+ bool existsIn(const QDir &workspace) const;
+ bool isFileIn(const QDir &workspace) const;
+
+ QString relativeFilePath() const;
+ QString absoluteFilePathIn(const QDir &workspace) const;
+
+ static LiveDocument resolve(const QDir &workspace, const QString &filePath);
+
+ friend inline bool operator==(const LiveDocument &d1, const LiveDocument &d2)
+ { return d1.m_relativeFilePath == d2.m_relativeFilePath; }
+ friend inline bool operator!=(const LiveDocument &d1, const LiveDocument &d2)
+ { return !(d1 == d2); }
+
+private:
+ QString m_relativeFilePath;
+ mutable QString m_errorString;
+};
+
+QDebug QMLLIVESHARED_EXPORT operator<<(QDebug dbg, const LiveDocument &document);
diff --git a/src/livehubengine.cpp b/src/livehubengine.cpp
index 6db5520..39208bf 100644
--- a/src/livehubengine.cpp
+++ b/src/livehubengine.cpp
@@ -55,7 +55,7 @@ LiveHubEngine::LiveHubEngine(QObject *parent)
, m_watcher(new Watcher(this))
, m_filePublishingActive(false)
{
- connect(m_watcher, SIGNAL(directoriesChanged(QStringList)), this, SLOT(directoriesChanged(QStringList)));
+ connect(m_watcher, &Watcher::directoriesChanged, this, &LiveHubEngine::directoriesChanged);
}
/*!
@@ -78,18 +78,18 @@ QString LiveHubEngine::workspace() const
/*!
* Sets the active document path to \a path.
- * Emits activateDocument() with the workspace relative path.
+ * Emits activateDocument() with this path.
*/
-void LiveHubEngine::setActivePath(const QString &path)
+void LiveHubEngine::setActivePath(const LiveDocument &path)
{
m_activePath = path;
- emit activateDocument(m_watcher->relativeFilePath(path));
+ emit activateDocument(m_activePath);
}
/*!
* Returns the active Document
*/
-QString LiveHubEngine::activePath() const
+LiveDocument LiveHubEngine::activePath() const
{
return m_activePath;
}
@@ -106,7 +106,7 @@ void LiveHubEngine::directoriesChanged(const QStringList &changes)
}
}
- emit activateDocument(m_watcher->relativeFilePath(m_activePath));
+ emit activateDocument(m_activePath);
}
/*!
@@ -132,10 +132,11 @@ void LiveHubEngine::publishDirectory(const QString& dirPath, bool fileChange)
if (!m_filePublishingActive) { return; }
QDirIterator iter(dirPath, QDir::Files);
while (iter.hasNext()) {
+ LiveDocument document = LiveDocument::resolve(m_watcher->directory(), iter.next());
if (fileChange)
- emit fileChanged(iter.next());
+ emit fileChanged(document);
else
- emit publishFile(iter.next());
+ emit publishFile(document);
}
}
@@ -162,21 +163,21 @@ void LiveHubEngine::setFilePublishingActive(bool on)
*/
/*!
- * \fn void LiveHubEngine::publishFile(const QString& document)
+ * \fn void LiveHubEngine::publishFile(const LiveDocument& document)
*
* This signal is emitted during publishing the directory to inform a connected
* node to publish the \a document to the remote device form the hub
*/
/*!
- * \fn void LiveHubEngine::fileChanged(const QString& document)
+ * \fn void LiveHubEngine::fileChanged(const LiveDocument& document)
*
* This signal is emitted during publishing a directory to inform a connected
* node that \a document has changed on the hub.
*/
/*!
- * \fn void LiveHubEngine::activateDocument(const QString& document)
+ * \fn void LiveHubEngine::activateDocument(const LiveDocument& document)
* The signal is emitted when the document identified by \a document has been activated
*/
diff --git a/src/livehubengine.h b/src/livehubengine.h
index 362c7db..266e07e 100644
--- a/src/livehubengine.h
+++ b/src/livehubengine.h
@@ -33,6 +33,7 @@
#include <QtCore>
+#include "livedocument.h"
#include "qmllive_global.h"
class Watcher;
@@ -46,17 +47,17 @@ public:
void setWorkspace(const QString& path);
QString workspace() const;
- QString activePath() const;
+ LiveDocument activePath() const;
public Q_SLOTS:
- void setActivePath(const QString& path);
+ void setActivePath(const LiveDocument& path);
void setFilePublishingActive(bool on);
void publishWorkspace();
Q_SIGNALS:
void beginPublishWorkspace();
void endPublishWorkspace();
- void publishFile(const QString& document);
- void fileChanged(const QString& document);
- void activateDocument(const QString& document);
+ void publishFile(const LiveDocument& document);
+ void fileChanged(const LiveDocument& document);
+ void activateDocument(const LiveDocument& document);
void workspaceChanged(const QString& workspace);
private Q_SLOTS:
void directoriesChanged(const QStringList& changes);
@@ -65,6 +66,6 @@ private:
private:
Watcher *m_watcher;
bool m_filePublishingActive;
- QString m_activePath;
+ LiveDocument m_activePath;
};
diff --git a/src/livenodeengine.cpp b/src/livenodeengine.cpp
index fd146c8..5feb843 100644
--- a/src/livenodeengine.cpp
+++ b/src/livenodeengine.cpp
@@ -57,14 +57,14 @@ const char OVERLAY_PATH_SEPARATOR = '-';
* \brief The LiveNodeEngine class instantiates QML components in cooperation with LiveHubEngine.
* \inmodule qmllive
*
- * LiveNodeEngine provides ways to reload qml documents based incoming requests
+ * LiveNodeEngine provides ways to reload QML documents based incoming requests
* from a hub. A hub can be connected via a RemotePublisher/RemoteReceiver pair.
*
* The primary use case is to allow loading of QML components instantiating
* QQuickWindow, i.e., inheriting QML Window. A fallbackView can be set in order
* to support also QML Item based components.
*
- * In Addition to showing qml-Files the LiveNodeEngine can be extended by plugins to show any other datatype.
+ * In Addition to showing QML files the LiveNodeEngine can be extended by plugins to show any other filetype.
* One need to set the Plugin path to the right destination and the LiveNodeEngine will load all the plugins
* it finds there.
*
@@ -119,12 +119,12 @@ public:
QDir overlay() const { return m_overlay; }
- QString reserve(const QString &document)
+ QString reserve(const LiveDocument &document)
{
QWriteLocker locker(&m_lock);
- QString overlayingPath = m_overlay.absoluteFilePath(document);
- m_mappings.insert(QUrl::fromLocalFile(m_base.absoluteFilePath(document)),
+ QString overlayingPath = document.absoluteFilePathIn(m_overlay);
+ m_mappings.insert(QUrl::fromLocalFile(document.absoluteFilePathIn(m_base)),
QUrl::fromLocalFile(overlayingPath));
return overlayingPath;
}
@@ -163,7 +163,7 @@ LiveNodeEngine::LiveNodeEngine(QObject *parent)
{
m_delayReload->setInterval(250);
m_delayReload->setSingleShot(true);
- connect(m_delayReload, SIGNAL(timeout()), this, SLOT(reloadDocument()));
+ connect(m_delayReload, &QTimer::timeout, this, &LiveNodeEngine::reloadDocument);
}
/*!
@@ -193,7 +193,6 @@ void LiveNodeEngine::setQmlEngine(QQmlEngine *qmlEngine)
m_qmlEngine = qmlEngine;
connect(m_qmlEngine.data(), &QQmlEngine::warnings, this, &LiveNodeEngine::logErrors);
- qmlEngine->setOutputWarningsToStandardError(false);
m_qmlEngine->rootContext()->setContextProperty("livert", m_runtime);
}
@@ -285,14 +284,93 @@ int LiveNodeEngine::rotation() const
}
/*!
- * Loads the given \a url onto the qml view. Clears any caches.
+ * Allows to initialize active document with an instance preloaded beyond
+ * LiveNodeEngine's control.
+ *
+ * This can be called at most once and only before a document has been loaded
+ * with loadDocument().
+ *
+ * \a document is the source of the component that was used to instantiate the
+ * \a object. \a window should be either the \a object itself or the
+ * fallbackView(). \a errors (if any) will be added to log.
+ *
+ * Note that \a window will be destroyed on next loadDocument() call unless it
+ * is the fallbackView(). \a object will be destroyed unconditionally.
+ */
+void LiveNodeEngine::usePreloadedDocument(const LiveDocument &document, QObject *object,
+ QQuickWindow *window, const QList<QQmlError> &errors)
+{
+ LIVE_ASSERT(m_activeFile.isNull(), return);
+ LIVE_ASSERT(!document.isNull(), return);
+
+ m_activeFile = document;
+
+ if (!m_activeFile.existsIn(m_workspace)) {
+ QQmlError error;
+ error.setUrl(QUrl::fromLocalFile(m_activeFile.absoluteFilePathIn(m_workspace)));
+ error.setDescription(tr("File not found"));
+ emit logErrors(QList<QQmlError>() << error);
+ }
+
+ m_object = object;
+ m_activeWindow = window;
+
+ if (m_activeWindow) {
+ m_activeWindowConnections << connect(m_activeWindow.data(), &QWindow::widthChanged,
+ this, &LiveNodeEngine::onSizeChanged);
+ m_activeWindowConnections << connect(m_activeWindow.data(), &QWindow::heightChanged,
+ this, &LiveNodeEngine::onSizeChanged);
+ onSizeChanged();
+ }
+
+ emit activeDocumentChanged(m_activeFile);
+ emit documentLoaded();
+ emit activeWindowChanged(m_activeWindow);
+ emit logErrors(errors);
+}
+
+/*!
+ * This is an overloaded function provided for convenience. It is suitable for
+ * use with QQmlApplicationEngine.
+ *
+ * Tries to resolve \a document against current workspace(). \a window is the
+ * root object. \a errors (if any) will be added to log.
+ */
+void LiveNodeEngine::usePreloadedDocument(const QString &document, QQuickWindow *window,
+ const QList<QQmlError> &errors)
+{
+ LIVE_ASSERT(m_activeFile.isNull(), return);
+
+ LiveDocument resolved = LiveDocument::resolve(workspace(), document);
+ if (resolved.isNull()) {
+ qWarning() << "Failed to resolve preloaded document path:" << document
+ << "Workspace: " << workspace();
+ return;
+ }
+
+ usePreloadedDocument(resolved, window, window, errors);
+}
+
+/*!
+ * Loads or reloads the given \a document onto the QML view. Clears any caches.
+ *
+ * The activeDocumentChanged() signal is emitted when this results in change of
+ * the activeDocument().
+ *
+ * \sa documentLoaded()
*/
-void LiveNodeEngine::loadDocument(const QUrl& url)
+void LiveNodeEngine::loadDocument(const LiveDocument& document)
{
- DEBUG << "LiveNodeEngine::loadDocument: " << url;
- m_activeFile = url;
+ DEBUG << "LiveNodeEngine::loadDocument: " << document;
+
+ LiveDocument oldActiveFile = m_activeFile;
+
+ m_activeFile = document;
- if (!m_activeFile.isEmpty())
+ if (m_activeFile != oldActiveFile)
+ emit activeDocumentChanged(m_activeFile);
+
+ if (!m_activeFile.isNull())
reloadDocument();
}
@@ -330,7 +408,7 @@ QUrl LiveNodeEngine::errorScreenUrl() const
}
/*!
- * Reloads the active qml document.
+ * Reloads the active QML document.
*
* Emits documentLoaded() when finished.
*
@@ -346,10 +424,8 @@ void LiveNodeEngine::reloadDocument()
}
// Do this unconditionally!
- if (m_fallbackView) {
+ if (m_fallbackView)
m_fallbackView->setSource(QUrl());
- m_fallbackView->close();
- }
m_activeWindow = 0;
@@ -360,26 +436,51 @@ void LiveNodeEngine::reloadDocument()
checkQmlFeatures();
+ qInfo() << "----------------------------------------";
+ qInfo() << "QmlLive: (Re)loading" << m_activeFile;
+
emit clearLog();
- const QUrl url = queryDocumentViewer(m_activeFile);
+ const QUrl originalUrl = QUrl::fromLocalFile(m_activeFile.absoluteFilePathIn(m_workspace));
+ const QUrl url = queryDocumentViewer(originalUrl);
- QScopedPointer<QQmlComponent> component(new QQmlComponent(m_qmlEngine, url));
- m_object = component->create();
+ auto showErrorScreen = [this] {
+ Q_ASSERT(m_fallbackView);
+ m_fallbackView->setResizeMode(QQuickView::SizeRootObjectToView);
+ m_fallbackView->setSource(errorScreenUrl());
+ m_activeWindow = m_fallbackView;
+ };
+
+ auto logError = [this, url](const QString &description) {
+ QQmlError error;
+ error.setObject(m_object);
+ error.setUrl(url);
+ error.setLine(0);
+ error.setColumn(0);
+ error.setDescription(description);
+ emit logErrors(QList<QQmlError>() << error);
+ };
+
+ QScopedPointer<QQmlComponent> component(new QQmlComponent(m_qmlEngine));
+ if (url.path().endsWith(QLatin1String(".qml"), Qt::CaseInsensitive)) {
+ component->loadUrl(url);
+ m_object = component->create();
+ } else if (url == originalUrl) {
+ logError(tr("LiveNodeEngine: Cannot display this file type"));
+ } else {
+ logError(tr("LiveNodeEngine: Internal error: Cannot display this file type"));
+ }
if (!component->isReady()) {
if (component->isLoading()) {
qCritical() << "Component did not load synchronously."
<< "URL:" << url.toString()
- << "(original URL:" << m_activeFile.toString() << ")";
+ << "(original URL:" << originalUrl.toString() << ")";
} else {
emit logErrors(component->errors());
delete m_object;
- if (m_fallbackView) {
- m_fallbackView->setResizeMode(QQuickView::SizeRootObjectToView);
- m_fallbackView->setSource(errorScreenUrl());
- m_activeWindow = m_fallbackView;
- }
+ if (m_fallbackView)
+ showErrorScreen();
}
} else if (QQuickWindow *window = qobject_cast<QQuickWindow *>(m_object)) {
// TODO (why) is this needed?
@@ -396,29 +497,14 @@ void LiveNodeEngine::reloadDocument()
m_fallbackView->setContent(url, component.take(), m_object);
m_activeWindow = m_fallbackView;
} else {
- QQmlError error;
- error.setObject(m_object);
- error.setUrl(url);
- error.setLine(0);
- error.setColumn(0);
- error.setDescription(tr("LiveNodeEngine: Cannot display this component: "
- "Root object is not a QQuickWindow and no LiveNodeEngine::fallbackView set."));
- emit logErrors(QList<QQmlError>() << error);
+ logError(tr("LiveNodeEngine: Cannot display this component: "
+ "Root object is not a QQuickWindow and no LiveNodeEngine::fallbackView set."));
}
} else {
- QQmlError error;
- error.setObject(m_object);
- error.setUrl(url);
- error.setLine(0);
- error.setColumn(0);
- error.setDescription(tr("LiveNodeEngine: Cannot display this component: "
- "Root object is not a QQuickWindow nor a QQuickItem."));
- emit logErrors(QList<QQmlError>() << error);
- if (m_fallbackView) {
- m_fallbackView->setResizeMode(QQuickView::SizeRootObjectToView);
- m_fallbackView->setSource(errorScreenUrl());
- m_activeWindow = m_fallbackView;
- }
+ logError(tr("LiveNodeEngine: Cannot display this component: "
+ "Root object is not a QQuickWindow nor a QQuickItem."));
+ if (m_fallbackView)
+ showErrorScreen();
}
if (m_activeWindow) {
@@ -432,6 +518,9 @@ void LiveNodeEngine::reloadDocument()
emit documentLoaded();
emit activeWindowChanged(m_activeWindow);
+ if (m_fallbackView && m_fallbackView != m_activeWindow)
+ m_fallbackView->close();
+
// Delay showing the window after activeWindowChanged is handled by
// WindowWidget::setHostedWindow() - it would be destroyed there anyway.
// (Applies when this is instantiated for the bench.)
@@ -444,7 +533,7 @@ void LiveNodeEngine::reloadDocument()
*
* The behavior of this function is controlled by WorkspaceOptions passed to setWorkspace().
*/
-void LiveNodeEngine::updateDocument(const QString &document, const QByteArray &content)
+void LiveNodeEngine::updateDocument(const LiveDocument &document, const QByteArray &content)
{
if (!(m_workspaceOptions & AllowUpdates)) {
return;
@@ -452,7 +541,7 @@ void LiveNodeEngine::updateDocument(const QString &document, const QByteArray &c
QString filePath = (m_workspaceOptions & UpdatesAsOverlay)
? m_overlayUrlInterceptor->reserve(document)
- : m_workspace.absoluteFilePath(document);
+ : document.absoluteFilePathIn(m_workspace);
QString dirPath = QFileInfo(filePath).absoluteDir().absolutePath();
QDir().mkpath(dirPath);
@@ -464,13 +553,13 @@ void LiveNodeEngine::updateDocument(const QString &document, const QByteArray &c
file.write(content);
file.close();
- if (!m_activeFile.isEmpty())
+ if (!m_activeFile.isNull())
delayReload();
}
/*!
- * Allows to adapt a \a url to display not native qml documents (e.g. images).
+ * Allows to adapt a \a url to display not native QML documents (e.g. images).
*/
QUrl LiveNodeEngine::queryDocumentViewer(const QUrl& url)
{
@@ -493,20 +582,6 @@ QUrl LiveNodeEngine::queryDocumentViewer(const QUrl& url)
}
/*!
- * Sets the document \a document to be shown
- */
-void LiveNodeEngine::setActiveDocument(const QString &document)
-{
- QUrl url;
- if (!document.isEmpty()) {
- url = QUrl::fromLocalFile(m_workspace.absoluteFilePath(document));
- }
-
- loadDocument(url);
- emit activateDocument(document);
-}
-
-/*!
* Returns the current workspace path.
*/
QString LiveNodeEngine::workspace() const
@@ -597,9 +672,9 @@ QString LiveNodeEngine::pluginPath() const
}
/*!
- * Returns the current active document url.
+ * Returns the current active document.
*/
-QUrl LiveNodeEngine::activeDocument() const
+LiveDocument LiveNodeEngine::activeDocument() const
{
return m_activeFile;
}
@@ -650,9 +725,13 @@ void LiveNodeEngine::onSizeChanged()
}
/*!
- * \fn void LiveNodeEngine::activateDocument(const QString& document)
+ * \fn void LiveNodeEngine::activeDocumentChanged(const LiveDocument& document)
+ *
+ * The document \a document was loaded with loadDocument() and is now the
+ * activeDocument(). This signal is only emitted when the new document differs
+ * from the previously loaded one.
*
- * The document \a document was activated
+ * \sa documentLoaded()
*/
/*!
diff --git a/src/livenodeengine.h b/src/livenodeengine.h
index df030e1..78eebfe 100644
--- a/src/livenodeengine.h
+++ b/src/livenodeengine.h
@@ -35,6 +35,7 @@
#include <QtQuick>
#include "contentadapterinterface.h"
+#include "livedocument.h"
#include "qmllive_global.h"
class LiveRuntime;
@@ -79,22 +80,26 @@ public:
void setPluginPath(const QString& path);
QString pluginPath() const;
- QUrl activeDocument() const;
+ LiveDocument activeDocument() const;
ContentAdapterInterface *activePlugin() const;
QQuickWindow *activeWindow() const;
+ void usePreloadedDocument(const LiveDocument &document, QObject *object, QQuickWindow *window,
+ const QList<QQmlError> &errors);
+ void usePreloadedDocument(const QString &document, QQuickWindow *window,
+ const QList<QQmlError> &errors);
+
public Q_SLOTS:
void setXOffset(int offset);
void setYOffset(int offset);
void setRotation(int rotation);
- void setActiveDocument(const QString& document);
- void loadDocument(const QUrl& url);
+ void loadDocument(const LiveDocument& document);
void delayReload();
virtual void reloadDocument();
- void updateDocument(const QString &document, const QByteArray &content);
+ void updateDocument(const LiveDocument &document, const QByteArray &content);
Q_SIGNALS:
- void activateDocument(const QString& document);
+ void activeDocumentChanged(const LiveDocument& document);
void clearLog();
void logIgnoreMessages(bool on);
void documentLoaded();
@@ -105,7 +110,7 @@ Q_SIGNALS:
protected:
virtual void initPlugins();
QList<ContentAdapterInterface*> m_plugins;
- QUrl m_activeFile;
+ LiveDocument m_activeFile;
LiveRuntime *m_runtime;
private Q_SLOTS:
diff --git a/src/liveruntime.cpp b/src/liveruntime.cpp
index bdfef98..22c8327 100644
--- a/src/liveruntime.cpp
+++ b/src/liveruntime.cpp
@@ -36,10 +36,10 @@
/*!
* \class LiveRuntime
- * \brief Collects properties to be used for an enhanced live runtime.
+ * \brief Collects properties to be used for an enhanced QmlLive runtime.
* \inmodule qmllive
*
- * This runtime is used in an live enhanced qml project to be able to access more
+ * This runtime is used in a live enhanced QML project to be able to access more
* advanced features. Currently it does nothing
*/
diff --git a/src/logreceiver.cpp b/src/logreceiver.cpp
index 5e3aaba..7cec063 100644
--- a/src/logreceiver.cpp
+++ b/src/logreceiver.cpp
@@ -50,7 +50,7 @@ LogReceiver::LogReceiver(QObject *parent) :
m_socket(new QUdpSocket(this))
{
setPort(45454);
- connect(m_socket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
+ connect(m_socket, &QAbstractSocket::readyRead, this, &LogReceiver::processPendingDatagrams);
}
/*!
diff --git a/src/previewGenerator/main.cpp b/src/previewGenerator/main.cpp
index 3ef884c..a17e66d 100644
--- a/src/previewGenerator/main.cpp
+++ b/src/previewGenerator/main.cpp
@@ -54,7 +54,7 @@ public:
PreviewServer()
: m_server(new QLocalServer())
{
- connect(m_server, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
+ connect(m_server, &QLocalServer::newConnection, this, &PreviewServer::onNewConnection);
}
bool listen()
@@ -89,7 +89,7 @@ private:
};
Q_DECLARE_LOGGING_CATEGORY(pg)
-Q_LOGGING_CATEGORY(pg, "PreviewGenerator", QtWarningMsg)
+Q_LOGGING_CATEGORY(pg, "PreviewGenerator", QtInfoMsg)
int main (int argc, char** argv)
{
diff --git a/src/qmlhelper.cpp b/src/qmlhelper.cpp
index 2b5d472..72dc1af 100644
--- a/src/qmlhelper.cpp
+++ b/src/qmlhelper.cpp
@@ -34,7 +34,7 @@
/*!
* \class QmlHelper
- * \brief Provides a set of helper functions to setup your qml viewer
+ * \brief Provides a set of helper functions to setup your QML viewer
* \inmodule qmllive
*/
@@ -66,11 +66,7 @@ void QmlHelper::loadDummyData(QQmlEngine *engine, const QString &workspace)
}
}
if (obj) {
-#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
qInfo() << "loaded dummy data: " << dir.filePath(entry);
-#else
- qWarning() << "loaded dummy data: " << dir.filePath(entry);
-#endif
entry.chop(4);
engine->rootContext()->setContextProperty(entry, obj);
obj->setParent(engine);
diff --git a/src/qmllive_global.h b/src/qmllive_global.h
index d64f3e9..cba8d4b 100755
--- a/src/qmllive_global.h
+++ b/src/qmllive_global.h
@@ -44,4 +44,28 @@
# define QMLLIVESHARED_EXPORT
#endif
+#if defined(QMLLIVE_VERSION)
+# define QMLLIVE_SOURCE
+#endif
+
+#if defined(QMLLIVE_SOURCE)
+
+# if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
+# define LIVE_ASSERT(cond, action) Q_ASSERT(cond)
+# else
+# define LIVE_ASSERT(cond, action) if (cond) {} else { \
+ QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical() \
+ << "Assertion \"" #cond "\" failed"; \
+ action; \
+ } do {} while (0)
+# endif
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
+# define QtInfoMsg QtWarningMsg
+# define qInfo qWarning
+# define qCInfo qCWarning
+#endif
+
+#endif // defined(QMLLIVE_SOURCE)
+
#endif // QMLLIVELIB_GLOBAL_H
diff --git a/src/remotelogger.cpp b/src/remotelogger.cpp
index 8aaec69..57a9ace 100644
--- a/src/remotelogger.cpp
+++ b/src/remotelogger.cpp
@@ -48,7 +48,7 @@ RemoteLogger::RemoteLogger(QObject *parent) :
m_socket(new QUdpSocket(this)) ,
m_port(45454)
{
- connect(this, SIGNAL(message(int,QString)), this, SLOT(broadcast(int,QString)));
+ connect(this, &Logger::message, this, &RemoteLogger::broadcast);
}
/*!
diff --git a/src/remotepublisher.cpp b/src/remotepublisher.cpp
index 99a643c..ca24924 100644
--- a/src/remotepublisher.cpp
+++ b/src/remotepublisher.cpp
@@ -31,6 +31,7 @@
#include "remotepublisher.h"
#include "ipc/ipcclient.h"
+#include "livedocument.h"
#include "livehubengine.h"
#ifdef QMLLIVE_DEBUG
@@ -57,19 +58,16 @@ RemotePublisher::RemotePublisher(QObject *parent)
, m_ipc(new IpcClient(this))
, m_hub(0)
{
- connect(m_ipc, SIGNAL(sentSuccessfully(QUuid)), this, SIGNAL(sentSuccessfully(QUuid)));
- connect(m_ipc, SIGNAL(sendingError(QUuid,QAbstractSocket::SocketError)),
- this, SIGNAL(sendingError(QUuid,QAbstractSocket::SocketError)));
- connect(m_ipc, SIGNAL(connectionError(QAbstractSocket::SocketError)),
- this, SIGNAL(connectionError(QAbstractSocket::SocketError)));
- connect(m_ipc, SIGNAL(connected()), this, SIGNAL(connected()));
- connect(m_ipc, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
-
- connect(m_ipc, SIGNAL(received(QString,QByteArray)), this, SLOT(handleCall(QString,QByteArray)));
-
- connect(m_ipc, SIGNAL(sentSuccessfully(QUuid)), this, SLOT(onSentSuccessfully(QUuid)));
- connect(m_ipc, SIGNAL(sendingError(QUuid,QAbstractSocket::SocketError)),
- this, SLOT(onSendingError(QUuid,QAbstractSocket::SocketError)));
+ connect(m_ipc, &IpcClient::sentSuccessfully, this, &RemotePublisher::sentSuccessfully);
+ connect(m_ipc, &IpcClient::sendingError, this, &RemotePublisher::sendingError);
+ connect(m_ipc, &IpcClient::connectionError, this, &RemotePublisher::connectionError);
+ connect(m_ipc, &IpcClient::connected, this, &RemotePublisher::connected);
+ connect(m_ipc, &IpcClient::disconnected, this, &RemotePublisher::disconnected);
+
+ connect(m_ipc, &IpcClient::received, this, &RemotePublisher::handleCall);
+
+ connect(m_ipc, &IpcClient::sentSuccessfully, this, &RemotePublisher::onSentSuccessfully);
+ connect(m_ipc, &IpcClient::sendingError, this, &RemotePublisher::onSendingError);
}
/*!
@@ -91,12 +89,12 @@ void RemotePublisher::registerHub(LiveHubEngine *hub)
disconnect(m_hub);
}
m_hub = hub;
- connect(hub, SIGNAL(activateDocument(QString)), this, SLOT(activateDocument(QString)));
- connect(hub, SIGNAL(fileChanged(QString)), this, SLOT(sendDocument(QString)));
- connect(hub, SIGNAL(publishFile(QString)), this, SLOT(sendDocument(QString)));
- connect(this, SIGNAL(needsPublishWorkspace()), hub, SLOT(publishWorkspace()));
- connect(hub, SIGNAL(beginPublishWorkspace()), this, SLOT(beginBulkSend()));
- connect(hub, SIGNAL(endPublishWorkspace()), this, SLOT(endBulkSend()));
+ connect(hub, &LiveHubEngine::activateDocument, this, &RemotePublisher::activateDocument);
+ connect(hub, &LiveHubEngine::fileChanged, this, &RemotePublisher::sendDocument);
+ connect(hub, &LiveHubEngine::publishFile, this, &RemotePublisher::sendDocument);
+ connect(this, &RemotePublisher::needsPublishWorkspace, hub, &LiveHubEngine::publishWorkspace);
+ connect(hub, &LiveHubEngine::beginPublishWorkspace, this, &RemotePublisher::beginBulkSend);
+ connect(hub, &LiveHubEngine::endPublishWorkspace, this, &RemotePublisher::endBulkSend);
}
/*!
@@ -134,15 +132,15 @@ void RemotePublisher::disconnectFromServer()
}
/*!
- * Send "activateDocument(QString)" to ipc-server on activate document.
+ * Send "activateDocument(QString)" to IPC-server on activate document.
* \a document defines the Document which should be activated
*/
-QUuid RemotePublisher::activateDocument(const QString &document)
+QUuid RemotePublisher::activateDocument(const LiveDocument &document)
{
DEBUG << "RemotePublisher::activateDocument" << document;
QByteArray bytes;
QDataStream out(&bytes, QIODevice::WriteOnly);
- out << document;
+ out << document.relativeFilePath();
return m_ipc->send("activateDocument(QString)", bytes);
}
@@ -165,10 +163,10 @@ QUuid RemotePublisher::endBulkSend()
}
/*!
- * Sends "sendDocument(QString)" using \a document as path to the document to be
+ * Sends "sendDocument(QString)" using \a document to identify the document to be
*send to via IPC.
*/
-QUuid RemotePublisher::sendDocument(const QString& document)
+QUuid RemotePublisher::sendDocument(const LiveDocument& document)
{
DEBUG << "RemotePublisher::sendDocument" << document;
return sendWholeDocument(document);
@@ -224,10 +222,10 @@ QUuid RemotePublisher::setRotation(int rotation)
/*!
Sends the \e sendWholeDocument with \a document as argument via IPC
*/
-QUuid RemotePublisher::sendWholeDocument(const QString& document)
+QUuid RemotePublisher::sendWholeDocument(const LiveDocument& document)
{
DEBUG << "RemotePublisher::sendWholeDocument" << document;
- QFile file(document);
+ QFile file(document.absoluteFilePathIn(m_workspace));
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "ERROR: can't open file: " << document;
return QUuid();
@@ -236,7 +234,7 @@ QUuid RemotePublisher::sendWholeDocument(const QString& document)
QByteArray bytes;
QDataStream out(&bytes, QIODevice::WriteOnly);
- out << m_workspace.relativeFilePath(document);
+ out << document.relativeFilePath();
out << data;
return m_ipc->send("sendDocument(QString,QByteArray)", bytes);
}
@@ -295,6 +293,19 @@ void RemotePublisher::handleCall(const QString &method, const QByteArray &conten
emit remoteLog(msgType, description, url, line, column);
} else if (method == "clearLog()") {
emit clearLog();
+ } else if (method == "activeDocumentChanged(QString)") {
+ QString path;
+
+ QDataStream in(content);
+ in >> path;
+
+ if (path.isEmpty() || !QDir::isRelativePath(path)) {
+ qCritical() << "Invalid argument to remote call activeDocumentChanged."
+ << "Relative file path expected:" << path;
+ return;
+ }
+
+ emit activeDocumentChanged(LiveDocument(path));
}
}
@@ -351,6 +362,13 @@ void RemotePublisher::handleCall(const QString &method, const QByteArray &conten
* to indicate the client asks for (re)sending all workspace documents.
*/
+/*!
+ * \fn RemotePublisher::activeDocumentChanged(const LiveDocument &document)
+ *
+ * The signal is emitted after receiving the activeDocumentChanged IPC call,
+ * to indicate the client's active \a document has changed.
+ */
+
/*! \fn RemotePublisher::sentSuccessfully(const QUuid& uuid)
*
* The signal is emitted after the package identified by \a uuid has been send
diff --git a/src/remotepublisher.h b/src/remotepublisher.h
index 8d69f9b..13840f4 100644
--- a/src/remotepublisher.h
+++ b/src/remotepublisher.h
@@ -36,6 +36,7 @@
#include "qmllive_global.h"
+class LiveDocument;
class LiveHubEngine;
class IpcClient;
@@ -57,6 +58,7 @@ Q_SIGNALS:
void connectionError(QAbstractSocket::SocketError error);
void needsPinAuthentication();
void needsPublishWorkspace();
+ void activeDocumentChanged(const LiveDocument &document);
void pinOk(bool ok);
void remoteLog(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1);
void clearLog();
@@ -64,10 +66,10 @@ Q_SIGNALS:
public Q_SLOTS:
void setWorkspace(const QString &path);
void disconnectFromServer();
- QUuid activateDocument(const QString& document);
+ QUuid activateDocument(const LiveDocument& document);
QUuid beginBulkSend();
QUuid endBulkSend();
- QUuid sendDocument(const QString& document);
+ QUuid sendDocument(const LiveDocument& document);
QUuid checkPin(const QString& pin);
QUuid setXOffset(int offset);
QUuid setYOffset(int offset);
@@ -75,7 +77,7 @@ public Q_SLOTS:
private Q_SLOTS:
void handleCall(const QString &method, const QByteArray &content);
- QUuid sendWholeDocument(const QString &document);
+ QUuid sendWholeDocument(const LiveDocument &document);
void onSentSuccessfully(const QUuid& uuid);
void onSendingError(const QUuid& uuid, QAbstractSocket::SocketError socketError);
diff --git a/src/remotereceiver.cpp b/src/remotereceiver.cpp
index 5877892..0175d44 100644
--- a/src/remotereceiver.cpp
+++ b/src/remotereceiver.cpp
@@ -82,11 +82,16 @@ RemoteReceiver::RemoteReceiver(QObject *parent)
, m_client(0)
, m_bulkUpdateInProgress(false)
, m_updateDocumentsOnConnectState(UpdateNotStarted)
+ , m_logSentPosition(0)
{
- connect(m_server, SIGNAL(received(QString,QByteArray)), this, SLOT(handleCall(QString,QByteArray)));
- connect(m_server, SIGNAL(clientConnected(QTcpSocket*)), this, SLOT(onClientConnected(QTcpSocket*)));
- connect(m_server, SIGNAL(clientConnected(QHostAddress)), this, SIGNAL(clientConnected(QHostAddress)));
- connect(m_server, SIGNAL(clientDisconnected(QHostAddress)), this, SIGNAL(clientDisconnected(QHostAddress)));
+ void (IpcServer::*IpcServer__clientConnected_socket)(QTcpSocket*) = &IpcServer::clientConnected;
+ void (IpcServer::*IpcServer__clientConnected_address)(const QHostAddress &) = &IpcServer::clientConnected;
+ void (IpcServer::*IpcServer__clientDisconnected_address)(const QHostAddress &) = &IpcServer::clientDisconnected;
+
+ connect(m_server, &IpcServer::received, this, &RemoteReceiver::handleCall);
+ connect(m_server, IpcServer__clientConnected_socket, this, &RemoteReceiver::onClientConnected);
+ connect(m_server, IpcServer__clientConnected_address, this, &RemoteReceiver::clientConnected);
+ connect(m_server, IpcServer__clientDisconnected_address, this, &RemoteReceiver::clientDisconnected);
}
/*!
@@ -101,11 +106,7 @@ bool RemoteReceiver::listen(int port, ConnectionOptions options)
m_server->listen(port);
if (m_connectionOptions & BlockingConnect) {
-#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
- qWarning() << "Waiting for connection from QML Live bench…";
-#else
- qInfo() << "Waiting for connection from QML Live bench…";
-#endif
+ qInfo() << "Waiting for connection from QmlLive Bench…";
QEventLoop loop;
@@ -216,6 +217,7 @@ void RemoteReceiver::handleCall(const QString &method, const QByteArray &content
emit endBulkUpdate();
if (m_updateDocumentsOnConnectState == UpdateStarted) {
m_updateDocumentsOnConnectState = UpdateFinished;
+ finishConnectionInitialization();
emit updateDocumentsOnConnectFinished(true);
}
} else {
@@ -227,13 +229,13 @@ void RemoteReceiver::handleCall(const QString &method, const QByteArray &content
QDataStream in(content);
in >> document;
in >> data;
- emit updateDocument(document, data);
+ emit updateDocument(LiveDocument(document), data);
} else if (method == "activateDocument(QString)") {
QString document;
QDataStream in(content);
in >> document;
qDebug() << "\tactivate document: " << document;
- emit activateDocument(document);
+ emit activateDocument(LiveDocument(document));
} else if (method == "ping()") {
if (m_client)
m_client->send("pong()", QByteArray());
@@ -247,13 +249,14 @@ void RemoteReceiver::registerNode(LiveNodeEngine *node)
{
if (m_node) { disconnect(m_node); }
m_node = node;
- connect(m_node, SIGNAL(logErrors(QList<QQmlError>)), this, SLOT(appendToLog(QList<QQmlError>)));
- connect(m_node, SIGNAL(clearLog()), this, SLOT(clearLog()));
- connect(this, SIGNAL(activateDocument(QString)), m_node, SLOT(setActiveDocument(QString)));
- connect(this, SIGNAL(updateDocument(QString,QByteArray)), m_node, SLOT(updateDocument(QString,QByteArray)));
- connect(this, SIGNAL(xOffsetChanged(int)), m_node, SLOT(setXOffset(int)));
- connect(this, SIGNAL(yOffsetChanged(int)), m_node, SLOT(setYOffset(int)));
- connect(this, SIGNAL(rotationChanged(int)), m_node, SLOT(setRotation(int)));
+ connect(m_node, &LiveNodeEngine::logErrors, this, &RemoteReceiver::appendToLog);
+ connect(m_node, &LiveNodeEngine::clearLog, this, &RemoteReceiver::clearLog);
+ connect(m_node, &LiveNodeEngine::activeDocumentChanged, this, &RemoteReceiver::onActiveDocumentChanged);
+ connect(this, &RemoteReceiver::activateDocument, m_node, &LiveNodeEngine::loadDocument);
+ connect(this, &RemoteReceiver::updateDocument, m_node, &LiveNodeEngine::updateDocument);
+ connect(this, &RemoteReceiver::xOffsetChanged, m_node, &LiveNodeEngine::setXOffset);
+ connect(this, &RemoteReceiver::yOffsetChanged, m_node, &LiveNodeEngine::setYOffset);
+ connect(this, &RemoteReceiver::rotationChanged, m_node, &LiveNodeEngine::setRotation);
}
/*!
@@ -293,21 +296,41 @@ void RemoteReceiver::onClientDisconnected(QTcpSocket *socket)
}
void RemoteReceiver::maybeStartUpdateDocumentsOnConnect()
{
- if (!(m_connectionOptions & UpdateDocumentsOnConnect))
- return;
-
- if (m_updateDocumentsOnConnectState == UpdateNotStarted) {
+ if (m_connectionOptions & UpdateDocumentsOnConnect
+ && m_updateDocumentsOnConnectState == UpdateNotStarted) {
m_client->send("needsPublishWorkspace()", QByteArray());
m_updateDocumentsOnConnectState = UpdateRequested;
+ } else {
+ finishConnectionInitialization();
}
}
+void RemoteReceiver::finishConnectionInitialization()
+{
+ if (!m_node->activeDocument().isNull())
+ onActiveDocumentChanged(m_node->activeDocument());
+
+ m_logSentPosition = 0;
+ flushLog();
+}
+
/*!
* Called to send \a errors to remote for remote logging
*/
void RemoteReceiver::appendToLog(const QList<QQmlError> &errors)
{
- foreach (const QQmlError &err, errors) {
+ m_log.append(errors);
+
+ if (!m_client)
+ return;
+
+ flushLog();
+}
+
+void RemoteReceiver::flushLog()
+{
+ for (; m_logSentPosition < m_log.count(); ++m_logSentPosition) {
+ const QQmlError &err = m_log.at(m_logSentPosition);
if (!err.isValid())
continue;
@@ -337,11 +360,32 @@ void RemoteReceiver::appendToLog(const QList<QQmlError> &errors)
*/
void RemoteReceiver::clearLog()
{
+ m_log.clear();
+ m_logSentPosition = 0;
+
+ if (!m_client)
+ return;
+
m_client->send("clearLog()", QByteArray());
}
/*!
- * \fn void RemoteReceiver::activateDocument(const QString& document)
+ * Called to notify bench about active document change
+ */
+void RemoteReceiver::onActiveDocumentChanged(const LiveDocument &document)
+{
+ if (!m_client)
+ return;
+
+ QByteArray bytes;
+ QDataStream out(&bytes, QIODevice::WriteOnly);
+ out << document.relativeFilePath();
+
+ m_client->send("activeDocumentChanged(QString)", bytes);
+}
+
+/*!
+ * \fn void RemoteReceiver::activateDocument(const LiveDocument& document)
*
* This signal is emitted when the remote active document \a document has changed
*/
@@ -410,7 +454,7 @@ void RemoteReceiver::clearLog()
*/
/*!
- * \fn void RemoteReceiver::updateDocument(const QString &document, const QByteArray &content)
+ * \fn void RemoteReceiver::updateDocument(const LiveDocument &document, const QByteArray &content)
*
* This signal is emitted to notify that a \a document has changed its \a content
*/
diff --git a/src/remotereceiver.h b/src/remotereceiver.h
index aba3eed..4309a30 100644
--- a/src/remotereceiver.h
+++ b/src/remotereceiver.h
@@ -38,6 +38,7 @@
#include "qmllive_global.h"
+class LiveDocument;
class LiveNodeEngine;
class IpcServer;
class IpcClient;
@@ -80,7 +81,7 @@ public:
void setMaxConnections(int max);
Q_SIGNALS:
- void activateDocument(const QString& document);
+ void activateDocument(const LiveDocument& document);
void reload();
void clientConnected(const QHostAddress& address);
void clientDisconnected(const QHostAddress& address);
@@ -91,17 +92,22 @@ Q_SIGNALS:
void beginBulkUpdate();
void endBulkUpdate();
void updateDocumentsOnConnectFinished(bool ok);
- void updateDocument(const QString &document, const QByteArray &content);
+ void updateDocument(const LiveDocument &document, const QByteArray &content);
private Q_SLOTS:
void handleCall(const QString& method, const QByteArray& content);
void appendToLog(const QList<QQmlError> &errors);
void clearLog();
+ void onActiveDocumentChanged(const LiveDocument &document);
void onClientConnected(QTcpSocket *socket);
void onClientDisconnected(QTcpSocket *socket);
void maybeStartUpdateDocumentsOnConnect();
+ void finishConnectionInitialization();
+
+private:
+ void flushLog();
private:
IpcServer *m_server;
@@ -116,6 +122,9 @@ private:
ConnectionOptions m_connectionOptions;
bool m_bulkUpdateInProgress;
UpdateState m_updateDocumentsOnConnectState;
+
+ QList<QQmlError> m_log;
+ int m_logSentPosition;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(RemoteReceiver::ConnectionOptions)
diff --git a/src/runtime/main.cpp b/src/runtime/main.cpp
index db26054..3058e24 100644
--- a/src/runtime/main.cpp
+++ b/src/runtime/main.cpp
@@ -75,13 +75,13 @@ static void parseArguments(const QStringList &arguments)
parser.addPositionalArgument("workspace", "workspace folder to watch");
- QCommandLineOption ipcPortOption("ipcport", "the port the ipc shall listen on, default is 10234", "ipcport");
+ QCommandLineOption ipcPortOption("ipcport", "the port the IPC shall listen on, default is 10234", "ipcport");
parser.addOption(ipcPortOption);
- QCommandLineOption pluginPathOption("pluginpath", "path to qmllive plugins", "pluginpath");
+ QCommandLineOption pluginPathOption("pluginpath", "path to QmlLive plugins", "pluginpath");
parser.addOption(pluginPathOption);
- QCommandLineOption importPathOption("importpath", "path to qml import path. Can appear multiple times", "importpath");
+ QCommandLineOption importPathOption("importpath", "path to QML import path. Can appear multiple times", "importpath");
parser.addOption(importPathOption);
QCommandLineOption stayOnTopOption("stayontop", "keep viewer window on top");
@@ -189,12 +189,13 @@ int main(int argc, char** argv)
engine.setFallbackView(&fallbackView);
engine.setWorkspace(options.workspace, workspaceOptions);
engine.setPluginPath(options.pluginPath);
- engine.loadDocument(QUrl("qrc:/qml/qmlsplash/splash-qt5.qml"));
RemoteReceiver receiver;
receiver.registerNode(&engine);
if (!receiver.listen(options.ipcPort, connectionOptions))
return EXIT_FAILURE;
+ fallbackView.setSource(QUrl("qrc:/qml/qmlsplash/splash-qt5.qml"));
+
int ret = app.exec();
return ret;
diff --git a/src/src.pri b/src/src.pri
index 8a629e6..1af18e4 100644
--- a/src/src.pri
+++ b/src/src.pri
@@ -8,6 +8,7 @@ DEFINES += NO_LIBRSYNC
SOURCES += \
$$PWD/watcher.cpp \
+ $$PWD/livedocument.cpp \
$$PWD/livehubengine.cpp \
$$PWD/livenodeengine.cpp \
$$PWD/qmlhelper.cpp \
@@ -22,6 +23,7 @@ SOURCES += \
$$PWD/fontadapter.cpp
public_headers += \
+ $$PWD/livedocument.h \
$$PWD/livehubengine.h \
$$PWD/livenodeengine.h \
$$PWD/qmlhelper.h \
diff --git a/src/watcher.cpp b/src/watcher.cpp
index c97fa8f..2be3abb 100644
--- a/src/watcher.cpp
+++ b/src/watcher.cpp
@@ -48,8 +48,8 @@ Watcher::Watcher(QObject *parent)
, m_watcher(new QFileSystemWatcher(this))
, m_waitTimer(new QTimer(this))
{
- connect(m_watcher, SIGNAL(directoryChanged(QString)), this, SLOT(recordChange(QString)));
- connect(m_waitTimer, SIGNAL(timeout()), this, SLOT(notifyChanges()));
+ connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &Watcher::recordChange);
+ connect(m_waitTimer, &QTimer::timeout, this, &Watcher::notifyChanges);
m_waitTimer->setInterval(100);
m_waitTimer->setSingleShot(true);
}
@@ -105,15 +105,6 @@ void Watcher::addDirectoriesRecursively(const QString &path)
}
-/*!
- Returns the given path relative to the watcher's Directory
- /sa setDirectory, directory()
- */
-QString Watcher::relativeFilePath(const QString &path)
-{
- return m_rootDir.relativeFilePath(path);
-}
-
void Watcher::recordChange(const QString &path)
{
// qDebug() << "Watcher::recordChange: " << path;
diff --git a/src/watcher.h b/src/watcher.h
index 67f39ae..a17e28a 100644
--- a/src/watcher.h
+++ b/src/watcher.h
@@ -40,7 +40,6 @@ public:
explicit Watcher(QObject *parent = 0);
void setDirectory(const QString& path);
QString directory() const;
- QString relativeFilePath(const QString& path);
private Q_SLOTS:
void recordChange(const QString &path);
void notifyChanges();
diff --git a/src/widgets/filesystemmodel.cpp b/src/widgets/filesystemmodel.cpp
index f375f43..f3622b9 100644
--- a/src/widgets/filesystemmodel.cpp
+++ b/src/widgets/filesystemmodel.cpp
@@ -62,6 +62,7 @@ Qt::ItemFlags FileSystemModel::flags(const QModelIndex &index) const
Qt::ItemFlags f = QFileSystemModel::flags(index);
if (isDir(index)) {
+ f &= ~Qt::ItemIsDragEnabled;
if (m_dirSelectable)
return f;
else
diff --git a/src/widgets/logview.cpp b/src/widgets/logview.cpp
index 2117921..f291faf 100644
--- a/src/widgets/logview.cpp
+++ b/src/widgets/logview.cpp
@@ -47,7 +47,7 @@ LogView::LogView(bool createLogger, QWidget *parent)
if (createLogger) {
m_logger = new Logger(this);
- connect(m_logger, SIGNAL(message(int,QString)), this, SLOT(appendToLog(int,QString)));
+ connect(m_logger, &Logger::message, this, &LogView::appendToLog);
}
}
@@ -104,7 +104,7 @@ void LogView::appendToLog(int type, const QString &msg, const QUrl &url, int lin
m_log->appendHtml(s);
}
-void LogView::appendToLog(const QList<QQmlError> &errors)
+void LogView::appendAllToLog(const QList<QQmlError> &errors)
{
foreach (const QQmlError &err, errors) {
if (!err.isValid())
diff --git a/src/widgets/logview.h b/src/widgets/logview.h
index 7ecdd7f..7d1874a 100644
--- a/src/widgets/logview.h
+++ b/src/widgets/logview.h
@@ -53,7 +53,7 @@ public slots:
void setIgnoreMessages(bool ignoreMessages);
void clear();
void appendToLog(int type, const QString &msg, const QUrl &url = QUrl(), int line = -1, int column = -1);
- void appendToLog(const QList<QQmlError> &errors);
+ void appendAllToLog(const QList<QQmlError> &errors);
private:
QPlainTextEdit *m_log;
diff --git a/src/widgets/workspacedelegate.cpp b/src/widgets/workspacedelegate.cpp
index 0f886fd..8f61cee 100644
--- a/src/widgets/workspacedelegate.cpp
+++ b/src/widgets/workspacedelegate.cpp
@@ -31,9 +31,12 @@
#include "workspacedelegate.h"
-WorkspaceDelegate::WorkspaceDelegate(FileSystemModel *model, QObject *parent) :
- QStyledItemDelegate(parent),
- m_model(model)
+#include "filesystemmodel.h"
+#include "workspaceview.h"
+
+WorkspaceDelegate::WorkspaceDelegate(WorkspaceView *view) :
+ QStyledItemDelegate(view),
+ m_view(view)
{
}
@@ -42,11 +45,31 @@ void WorkspaceDelegate::initStyleOption(QStyleOptionViewItem *option, const QMod
QStyledItemDelegate::initStyleOption(option, index);
if (option) {
- if (m_model->isDir(index))
+ QString path = m_view->model()->filePath(index);
+
+ // Do not paint selected items any special way - only the current item
+ // and the item corresponding to the active document will be
+ // highlighted.
+ option->state &= ~QStyle::State_Selected;
+
+ // Highlighting in the view is suppressed with customized palette.
+ // See WorkspaceView's constructor.
+ QColor highlight = qApp->palette().color(QPalette::Highlight);
+ QColor highlightedText = qApp->palette().color(QPalette::HighlightedText);
+ option->palette.setColor(QPalette::Highlight, highlight);
+ option->palette.setColor(QPalette::HighlightedText, highlightedText);
+
+ LiveDocument document = LiveDocument::resolve(m_view->rootPath(), path);
+ if (document == m_view->activeDocument()) {
+ option->backgroundBrush = highlight;
+ option->palette.setColor(QPalette::Base, highlight);
+ option->palette.setColor(QPalette::Text, highlightedText);
+ }
+
+ if (m_view->model()->isDir(index))
return;
- QString path = m_model->filePath(index);
- foreach (QString type, m_model->allowedTypesFilter())
+ foreach (QString type, m_view->model()->allowedTypesFilter())
{
if (path.contains(QRegExp(type, Qt::CaseInsensitive, QRegExp::Wildcard)))
return;
diff --git a/src/widgets/workspacedelegate.h b/src/widgets/workspacedelegate.h
index ad1572d..2d0451a 100644
--- a/src/widgets/workspacedelegate.h
+++ b/src/widgets/workspacedelegate.h
@@ -32,18 +32,19 @@
#pragma once
#include <QStyledItemDelegate>
-#include "filesystemmodel.h"
+
+class WorkspaceView;
class WorkspaceDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
- explicit WorkspaceDelegate(FileSystemModel* model, QObject *parent = 0);
+ explicit WorkspaceDelegate(WorkspaceView *view);
virtual void initStyleOption(QStyleOptionViewItem * option, const QModelIndex & index )const;
private:
- FileSystemModel* m_model;
+ WorkspaceView* m_view;
};
diff --git a/src/widgets/workspaceview.cpp b/src/widgets/workspaceview.cpp
index d6523ab..a1f26f8 100644
--- a/src/widgets/workspaceview.cpp
+++ b/src/widgets/workspaceview.cpp
@@ -57,8 +57,16 @@ WorkspaceView::WorkspaceView(QWidget *parent)
m_view->hideColumn(2); // type
m_view->hideColumn(3); // modified time
- m_view->setItemDelegate(new WorkspaceDelegate(m_model, this));
- connect(m_view, SIGNAL(activated(QModelIndex)), this, SLOT(indexActivated(QModelIndex)));
+ // Prevent view highlighting background of a selected row. Only the
+ // active-document's row should be highlighted. See also
+ // WorkspaceDelegate::initStyleOption()
+ QPalette noHighlightPalette = palette();
+ noHighlightPalette.setColor(QPalette::Highlight, palette().color(QPalette::Base));
+ noHighlightPalette.setColor(QPalette::HighlightedText, palette().color(QPalette::Text));
+ m_view->setPalette(noHighlightPalette);
+
+ m_view->setItemDelegate(new WorkspaceDelegate(this));
+ connect(m_view, &QTreeView::activated, this, &WorkspaceView::indexActivated);
m_model->setAllowedTypesFilter(QStringList() << "*.qml" << "*.png" << "*.otf" << "*.ttf");
@@ -68,7 +76,6 @@ WorkspaceView::WorkspaceView(QWidget *parent)
layout->setMargin(1);
setLayout(layout);
-
m_view->setDragEnabled(true);
m_view->setDragDropMode(QAbstractItemView::DragOnly);
}
@@ -85,17 +92,17 @@ void WorkspaceView::setRootPath(const QString &dirPath)
/*!
* Activates the document by the given \a path
*/
-void WorkspaceView::activateDocument(const QString &path)
+void WorkspaceView::activateDocument(const LiveDocument &path)
{
//qDebug() << "WorkspaceView::activateDocument" << path;
- QModelIndex index = m_model->index(path);
+ QModelIndex index = m_model->index(path.absoluteFilePathIn(rootPath()));
selectIndex(index);
}
void WorkspaceView::activateRootPath()
{
selectIndex(m_rootIndex);
- emit pathActivated(m_model->rootPath());
+ emit pathActivated(LiveDocument(QStringLiteral(".")));
}
void WorkspaceView::goUp()
@@ -110,7 +117,7 @@ void WorkspaceView::goUp()
/*!
* Returns the active, selected document.
*/
-QString WorkspaceView::activeDocument() const
+LiveDocument WorkspaceView::activeDocument() const
{
return m_currentDocument;
}
@@ -140,8 +147,14 @@ void WorkspaceView::indexActivated(const QModelIndex &index)
QString path = m_model->filePath(index);
- m_currentDocument = path;
- emit pathActivated(path);
+ LiveDocument oldDocument = m_currentDocument;
+
+ m_currentDocument = LiveDocument::resolve(m_model->rootDirectory(), path);
+ emit pathActivated(m_currentDocument);
+ m_view->update(index);
+
+ if (!oldDocument.isNull())
+ m_view->update(m_model->index(oldDocument.absoluteFilePathIn(rootPath())));
}
void WorkspaceView::selectIndex(const QModelIndex &index)
diff --git a/src/widgets/workspaceview.h b/src/widgets/workspaceview.h
index 4e1c9c3..dab0df6 100644
--- a/src/widgets/workspaceview.h
+++ b/src/widgets/workspaceview.h
@@ -31,6 +31,8 @@
#pragma once
+#include "livedocument.h"
+
#include <QtGui>
#include <QtWidgets>
@@ -41,19 +43,20 @@ class WorkspaceView : public QWidget
Q_OBJECT
public:
explicit WorkspaceView(QWidget *parent = 0);
- QString activeDocument() const;
+ FileSystemModel *model() const { return m_model; }
+ LiveDocument activeDocument() const;
QString rootPath() const;
void setDirectoriesSelectable(bool enabled);
bool directoriesSelectable() const;
public Q_SLOTS:
void setRootPath(const QString& dirPath);
- void activateDocument(const QString& path);
+ void activateDocument(const LiveDocument& path);
void activateRootPath();
void goUp();
Q_SIGNALS:
- void pathActivated(const QString& path);
+ void pathActivated(const LiveDocument& path);
private Q_SLOTS:
void indexActivated(const QModelIndex& index);
@@ -63,5 +66,5 @@ private:
QTreeView *m_view;
FileSystemModel *m_model;
QModelIndex m_rootIndex;
- QString m_currentDocument;
+ LiveDocument m_currentDocument;
};
diff --git a/tests/testipc/tst_testipc.cpp b/tests/testipc/tst_testipc.cpp
index f73d37a..197b4d2 100644
--- a/tests/testipc/tst_testipc.cpp
+++ b/tests/testipc/tst_testipc.cpp
@@ -60,21 +60,21 @@ private Q_SLOTS:
void call() {
IpcServer peer1;
peer1.listen(10234);
- connect(&peer1, SIGNAL(received(QString,QByteArray)), this, SLOT(handleCall(QString,QByteArray)));
+ connect(&peer1, &IpcServer::received, this, &TestIpc::handleCall);
IpcClient peer2;
peer2.connectToServer("127.0.0.1", 10234);
QByteArray bytes;
QDataStream stream(&bytes, QIODevice::ReadWrite);
stream << QString("Hello IPC!");
peer2.send("echo(QString)", bytes);
- QSignalSpy received(&peer1, SIGNAL(received(QString,QByteArray)));
+ QSignalSpy received(&peer1, &IpcServer::received);
QTRY_COMPARE(received.count(), 1);
}
void sendFile() {
IpcServer peer1;
peer1.listen(10234);
- connect(&peer1, SIGNAL(received(QString,QByteArray)), this, SLOT(handleCall(QString,QByteArray)));
+ connect(&peer1, &IpcServer::received, this, &TestIpc::handleCall);
IpcClient peer2;
peer2.connectToServer("127.0.0.1", 10234);
QByteArray bytes;
@@ -83,7 +83,7 @@ private Q_SLOTS:
stream << filePath;
stream << QString("hello").toLatin1();
peer2.send("sendFile(QString,QByteArray)", bytes);
- QSignalSpy received(&peer1, SIGNAL(received(QString,QByteArray)));
+ QSignalSpy received(&peer1, &IpcServer::received);
QTRY_COMPARE(received.count(), 1);
}
};